blob: ca027df66c1bc25d2af64b01bc24d11d9d7b8efc [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 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
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000030#ifndef WIN32
31#include <signal.h> // kill
32#include <unistd.h> // getpid
33#endif // WIN32
34
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000035#include "v8.h"
36
37#include "api.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000038#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000039#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000040#include "execution.h"
verwaest@chromium.org753aee42012-07-17 16:15:42 +000041#include "objects.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042#include "snapshot.h"
43#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000044#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000046#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000047#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000048
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000049static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000050
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000051static bool IsNaN(double x) {
52#ifdef WIN32
53 return _isnan(x);
54#else
55 return isnan(x);
56#endif
57}
58
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000059using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000060using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000061using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000063using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000064using ::v8::FunctionTemplate;
65using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000066using ::v8::HandleScope;
67using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000068using ::v8::Message;
69using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000070using ::v8::Object;
71using ::v8::ObjectTemplate;
72using ::v8::Persistent;
73using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000074using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000075using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000076using ::v8::TryCatch;
77using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000078using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000079using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000080
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000081
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000082static void ExpectString(const char* code, const char* expected) {
83 Local<Value> result = CompileRun(code);
84 CHECK(result->IsString());
85 String::AsciiValue ascii(result);
86 CHECK_EQ(expected, *ascii);
87}
88
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000089static void ExpectInt32(const char* code, int expected) {
90 Local<Value> result = CompileRun(code);
91 CHECK(result->IsInt32());
92 CHECK_EQ(expected, result->Int32Value());
93}
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000094
95static void ExpectBoolean(const char* code, bool expected) {
96 Local<Value> result = CompileRun(code);
97 CHECK(result->IsBoolean());
98 CHECK_EQ(expected, result->BooleanValue());
99}
100
101
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000102static void ExpectTrue(const char* code) {
103 ExpectBoolean(code, true);
104}
105
106
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000107static void ExpectFalse(const char* code) {
108 ExpectBoolean(code, false);
109}
110
111
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000112static void ExpectObject(const char* code, Local<Value> expected) {
113 Local<Value> result = CompileRun(code);
114 CHECK(result->Equals(expected));
115}
116
117
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000118static void ExpectUndefined(const char* code) {
119 Local<Value> result = CompileRun(code);
120 CHECK(result->IsUndefined());
121}
122
123
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000124static int signature_callback_count;
125static v8::Handle<Value> IncrementingSignatureCallback(
126 const v8::Arguments& args) {
127 ApiTestFuzzer::Fuzz();
128 signature_callback_count++;
129 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130 for (int i = 0; i < args.Length(); i++)
131 result->Set(v8::Integer::New(i), args[i]);
132 return result;
133}
134
135
136static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
137 ApiTestFuzzer::Fuzz();
138 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
139 for (int i = 0; i < args.Length(); i++) {
140 result->Set(v8::Integer::New(i), args[i]);
141 }
142 return result;
143}
144
145
146THREADED_TEST(Handles) {
147 v8::HandleScope scope;
148 Local<Context> local_env;
149 {
150 LocalContext env;
151 local_env = env.local();
152 }
153
154 // Local context should still be live.
155 CHECK(!local_env.IsEmpty());
156 local_env->Enter();
157
158 v8::Handle<v8::Primitive> undef = v8::Undefined();
159 CHECK(!undef.IsEmpty());
160 CHECK(undef->IsUndefined());
161
162 const char* c_source = "1 + 2 + 3";
163 Local<String> source = String::New(c_source);
164 Local<Script> script = Script::Compile(source);
165 CHECK_EQ(6, script->Run()->Int32Value());
166
167 local_env->Exit();
168}
169
170
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000171THREADED_TEST(IsolateOfContext) {
172 v8::HandleScope scope;
173 v8::Persistent<Context> env = Context::New();
174
175 CHECK(!env->InContext());
176 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
177 env->Enter();
178 CHECK(env->InContext());
179 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
180 env->Exit();
181 CHECK(!env->InContext());
182 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
183
184 env.Dispose();
185}
186
187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000188THREADED_TEST(ReceiverSignature) {
189 v8::HandleScope scope;
190 LocalContext env;
191 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
192 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
193 fun->PrototypeTemplate()->Set(
194 v8_str("m"),
195 v8::FunctionTemplate::New(IncrementingSignatureCallback,
196 v8::Handle<Value>(),
197 sig));
198 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
199 signature_callback_count = 0;
200 CompileRun(
201 "var o = new Fun();"
202 "o.m();");
203 CHECK_EQ(1, signature_callback_count);
204 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
205 sub_fun->Inherit(fun);
206 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
207 CompileRun(
208 "var o = new SubFun();"
209 "o.m();");
210 CHECK_EQ(2, signature_callback_count);
211
212 v8::TryCatch try_catch;
213 CompileRun(
214 "var o = { };"
215 "o.m = Fun.prototype.m;"
216 "o.m();");
217 CHECK_EQ(2, signature_callback_count);
218 CHECK(try_catch.HasCaught());
219 try_catch.Reset();
220 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
221 sub_fun->Inherit(fun);
222 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
223 CompileRun(
224 "var o = new UnrelFun();"
225 "o.m = Fun.prototype.m;"
226 "o.m();");
227 CHECK_EQ(2, signature_callback_count);
228 CHECK(try_catch.HasCaught());
229}
230
231
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000232THREADED_TEST(ArgumentSignature) {
233 v8::HandleScope scope;
234 LocalContext env;
235 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
236 cons->SetClassName(v8_str("Cons"));
237 v8::Handle<v8::Signature> sig =
238 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
239 v8::Handle<v8::FunctionTemplate> fun =
240 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
241 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
242 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
243
244 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000245 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
247 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000248 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249
250 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000251 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
253 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
254 cons1->SetClassName(v8_str("Cons1"));
255 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
256 cons2->SetClassName(v8_str("Cons2"));
257 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
258 cons3->SetClassName(v8_str("Cons3"));
259
260 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
261 v8::Handle<v8::Signature> wsig =
262 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
263 v8::Handle<v8::FunctionTemplate> fun2 =
264 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
265
266 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
267 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
268 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
269 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
270 v8::Handle<Value> value4 = CompileRun(
271 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
272 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000273 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000274
275 v8::Handle<Value> value5 = CompileRun(
276 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000277 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000278
279 v8::Handle<Value> value6 = CompileRun(
280 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000281 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000282
283 v8::Handle<Value> value7 = CompileRun(
284 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
285 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000286 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000287
288 v8::Handle<Value> value8 = CompileRun(
289 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000290 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000291}
292
293
294THREADED_TEST(HulIgennem) {
295 v8::HandleScope scope;
296 LocalContext env;
297 v8::Handle<v8::Primitive> undef = v8::Undefined();
298 Local<String> undef_str = undef->ToString();
299 char* value = i::NewArray<char>(undef_str->Length() + 1);
300 undef_str->WriteAscii(value);
301 CHECK_EQ(0, strcmp(value, "undefined"));
302 i::DeleteArray(value);
303}
304
305
306THREADED_TEST(Access) {
307 v8::HandleScope scope;
308 LocalContext env;
309 Local<v8::Object> obj = v8::Object::New();
310 Local<Value> foo_before = obj->Get(v8_str("foo"));
311 CHECK(foo_before->IsUndefined());
312 Local<String> bar_str = v8_str("bar");
313 obj->Set(v8_str("foo"), bar_str);
314 Local<Value> foo_after = obj->Get(v8_str("foo"));
315 CHECK(!foo_after->IsUndefined());
316 CHECK(foo_after->IsString());
317 CHECK_EQ(bar_str, foo_after);
318}
319
320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000321THREADED_TEST(AccessElement) {
322 v8::HandleScope scope;
323 LocalContext env;
324 Local<v8::Object> obj = v8::Object::New();
325 Local<Value> before = obj->Get(1);
326 CHECK(before->IsUndefined());
327 Local<String> bar_str = v8_str("bar");
328 obj->Set(1, bar_str);
329 Local<Value> after = obj->Get(1);
330 CHECK(!after->IsUndefined());
331 CHECK(after->IsString());
332 CHECK_EQ(bar_str, after);
333
334 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
335 CHECK_EQ(v8_str("a"), value->Get(0));
336 CHECK_EQ(v8_str("b"), value->Get(1));
337}
338
339
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340THREADED_TEST(Script) {
341 v8::HandleScope scope;
342 LocalContext env;
343 const char* c_source = "1 + 2 + 3";
344 Local<String> source = String::New(c_source);
345 Local<Script> script = Script::Compile(source);
346 CHECK_EQ(6, script->Run()->Int32Value());
347}
348
349
350static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000351 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000352 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000353 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354 return converted;
355}
356
357
358class TestResource: public String::ExternalStringResource {
359 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000360 explicit TestResource(uint16_t* data, int* counter = NULL)
361 : data_(data), length_(0), counter_(counter) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362 while (data[length_]) ++length_;
363 }
364
365 ~TestResource() {
366 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000367 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000368 }
369
370 const uint16_t* data() const {
371 return data_;
372 }
373
374 size_t length() const {
375 return length_;
376 }
377 private:
378 uint16_t* data_;
379 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000380 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381};
382
383
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384class TestAsciiResource: public String::ExternalAsciiStringResource {
385 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000386 explicit TestAsciiResource(const char* data, int* counter = NULL)
387 : data_(data), length_(strlen(data)), counter_(counter) { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000388
389 ~TestAsciiResource() {
390 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000391 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392 }
393
394 const char* data() const {
395 return data_;
396 }
397
398 size_t length() const {
399 return length_;
400 }
401 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000402 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000404 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405};
406
407
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408THREADED_TEST(ScriptUsingStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000409 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000410 const char* c_source = "1 + 2 * 3";
411 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
412 {
413 v8::HandleScope scope;
414 LocalContext env;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000415 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416 Local<String> source = String::NewExternal(resource);
417 Local<Script> script = Script::Compile(source);
418 Local<Value> value = script->Run();
419 CHECK(value->IsNumber());
420 CHECK_EQ(7, value->Int32Value());
421 CHECK(source->IsExternal());
422 CHECK_EQ(resource,
423 static_cast<TestResource*>(source->GetExternalStringResource()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000424 String::Encoding encoding = String::UNKNOWN_ENCODING;
425 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
426 source->GetExternalStringResourceBase(&encoding));
427 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000428 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000429 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 v8::internal::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000432 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000433 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000434}
435
436
437THREADED_TEST(ScriptUsingAsciiStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000438 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439 const char* c_source = "1 + 2 * 3";
440 {
441 v8::HandleScope scope;
442 LocalContext env;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000443 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
444 &dispose_count);
445 Local<String> source = String::NewExternal(resource);
446 CHECK(source->IsExternalAscii());
447 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
448 source->GetExternalAsciiStringResource());
449 String::Encoding encoding = String::UNKNOWN_ENCODING;
450 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
451 source->GetExternalStringResourceBase(&encoding));
452 CHECK_EQ(String::ASCII_ENCODING, encoding);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000453 Local<Script> script = Script::Compile(source);
454 Local<Value> value = script->Run();
455 CHECK(value->IsNumber());
456 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000458 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000459 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000461 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000462 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000463}
464
465
ager@chromium.org6f10e412009-02-13 10:11:16 +0000466THREADED_TEST(ScriptMakingExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000467 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000468 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
469 {
470 v8::HandleScope scope;
471 LocalContext env;
472 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000473 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000474 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
475 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000476 CHECK_EQ(source->IsExternal(), false);
477 CHECK_EQ(source->IsExternalAscii(), false);
478 String::Encoding encoding = String::UNKNOWN_ENCODING;
479 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
480 CHECK_EQ(String::ASCII_ENCODING, encoding);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000481 bool success = source->MakeExternal(new TestResource(two_byte_source,
482 &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000483 CHECK(success);
484 Local<Script> script = Script::Compile(source);
485 Local<Value> value = script->Run();
486 CHECK(value->IsNumber());
487 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000488 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000489 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000490 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000491 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000492 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000493 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000494}
495
496
497THREADED_TEST(ScriptMakingExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000498 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000499 const char* c_source = "1 + 2 * 3";
500 {
501 v8::HandleScope scope;
502 LocalContext env;
503 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000504 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
506 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000507 bool success = source->MakeExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000508 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000509 CHECK(success);
510 Local<Script> script = Script::Compile(source);
511 Local<Value> value = script->Run();
512 CHECK(value->IsNumber());
513 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000514 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000515 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000518 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000519 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000520}
521
522
ager@chromium.org5c838252010-02-19 08:53:10 +0000523TEST(MakingExternalStringConditions) {
524 v8::HandleScope scope;
525 LocalContext env;
526
527 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 HEAP->CollectGarbage(i::NEW_SPACE);
529 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000530
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000531 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000532 Local<String> small_string = String::New(two_byte_string);
533 i::DeleteArray(two_byte_string);
534
ager@chromium.org5c838252010-02-19 08:53:10 +0000535 // We should refuse to externalize newly created small string.
536 CHECK(!small_string->CanMakeExternal());
537 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
539 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000540 // Old space strings should be accepted.
541 CHECK(small_string->CanMakeExternal());
542
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000543 two_byte_string = AsciiToTwoByteString("small string 2");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000544 small_string = String::New(two_byte_string);
545 i::DeleteArray(two_byte_string);
546
ager@chromium.org5c838252010-02-19 08:53:10 +0000547 // We should refuse externalizing newly created small string.
548 CHECK(!small_string->CanMakeExternal());
549 for (int i = 0; i < 100; i++) {
550 String::Value value(small_string);
551 }
552 // Frequently used strings should be accepted.
553 CHECK(small_string->CanMakeExternal());
554
555 const int buf_size = 10 * 1024;
556 char* buf = i::NewArray<char>(buf_size);
557 memset(buf, 'a', buf_size);
558 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000559
560 two_byte_string = AsciiToTwoByteString(buf);
561 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000562 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000563 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000564 // Large strings should be immediately accepted.
565 CHECK(large_string->CanMakeExternal());
566}
567
568
569TEST(MakingExternalAsciiStringConditions) {
570 v8::HandleScope scope;
571 LocalContext env;
572
573 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 HEAP->CollectGarbage(i::NEW_SPACE);
575 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000576
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000577 Local<String> small_string = String::New("s1");
ager@chromium.org5c838252010-02-19 08:53:10 +0000578 // We should refuse to externalize newly created small string.
579 CHECK(!small_string->CanMakeExternal());
580 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
582 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000583 // Old space strings should be accepted.
584 CHECK(small_string->CanMakeExternal());
585
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000586 small_string = String::New("small string 2");
ager@chromium.org5c838252010-02-19 08:53:10 +0000587 // We should refuse externalizing newly created small string.
588 CHECK(!small_string->CanMakeExternal());
589 for (int i = 0; i < 100; i++) {
590 String::Value value(small_string);
591 }
592 // Frequently used strings should be accepted.
593 CHECK(small_string->CanMakeExternal());
594
595 const int buf_size = 10 * 1024;
596 char* buf = i::NewArray<char>(buf_size);
597 memset(buf, 'a', buf_size);
598 buf[buf_size - 1] = '\0';
599 Local<String> large_string = String::New(buf);
600 i::DeleteArray(buf);
601 // Large strings should be immediately accepted.
602 CHECK(large_string->CanMakeExternal());
603}
604
605
ager@chromium.org6f10e412009-02-13 10:11:16 +0000606THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000607 {
608 v8::HandleScope scope;
609 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
610 Local<String> string =
611 String::NewExternal(new TestResource(two_byte_string));
612 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
613 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
615 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
616 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000617 CHECK(isymbol->IsSymbol());
618 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000619 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
620 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000621}
622
623
624THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000625 {
626 v8::HandleScope scope;
627 const char* one_byte_string = "test string";
628 Local<String> string = String::NewExternal(
629 new TestAsciiResource(i::StrDup(one_byte_string)));
630 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
631 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
633 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
634 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000635 CHECK(isymbol->IsSymbol());
636 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000637 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
638 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000639}
640
641
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000642THREADED_TEST(ScavengeExternalString) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000643 i::FLAG_stress_compaction = false;
644 i::FLAG_gc_global = false;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000645 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000646 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000647 {
648 v8::HandleScope scope;
649 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
650 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000651 String::NewExternal(new TestResource(two_byte_string,
652 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000653 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000654 HEAP->CollectGarbage(i::NEW_SPACE);
655 in_new_space = HEAP->InNewSpace(*istring);
656 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000657 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000660 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
664THREADED_TEST(ScavengeExternalAsciiString) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000665 i::FLAG_stress_compaction = false;
666 i::FLAG_gc_global = false;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000667 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000668 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000669 {
670 v8::HandleScope scope;
671 const char* one_byte_string = "test string";
672 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000673 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000674 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 HEAP->CollectGarbage(i::NEW_SPACE);
676 in_new_space = HEAP->InNewSpace(*istring);
677 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000678 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000679 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000680 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000681 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000682}
683
684
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000685class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
686 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000687 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000688 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000689 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000690
691 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000692 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000693 dispose_(dispose) { }
694
695 void Dispose() {
696 ++dispose_calls;
697 if (dispose_) delete this;
698 }
699 private:
700 bool dispose_;
701};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000702
703
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000704int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000705int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000706
707
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000708TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000709 const char* c_source = "1 + 2 * 3";
710
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000711 // Use a stack allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000712 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000713 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
714 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000715 {
716 v8::HandleScope scope;
717 LocalContext env;
718 Local<String> source = String::NewExternal(&res_stack);
719 Local<Script> script = Script::Compile(source);
720 Local<Value> value = script->Run();
721 CHECK(value->IsNumber());
722 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000723 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000724 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000725 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000726 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000727 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000728 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000729 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000730
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000731 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000732 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000733 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
734 TestAsciiResource* res_heap =
735 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000736 {
737 v8::HandleScope scope;
738 LocalContext env;
739 Local<String> source = String::NewExternal(res_heap);
740 Local<Script> script = Script::Compile(source);
741 Local<Value> value = script->Run();
742 CHECK(value->IsNumber());
743 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000744 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000745 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000746 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000748 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000749 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000750 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000751}
752
753
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000754THREADED_TEST(StringConcat) {
755 {
756 v8::HandleScope scope;
757 LocalContext env;
758 const char* one_byte_string_1 = "function a_times_t";
759 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
760 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
761 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
762 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
763 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
764 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
765 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000766
767 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
768 Local<String> right = String::New(two_byte_source);
769 i::DeleteArray(two_byte_source);
770
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000771 Local<String> source = String::Concat(left, right);
772 right = String::NewExternal(
773 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
774 source = String::Concat(source, right);
775 right = String::NewExternal(
776 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
777 source = String::Concat(source, right);
778 right = v8_str(one_byte_string_2);
779 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000780
781 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
782 right = String::New(two_byte_source);
783 i::DeleteArray(two_byte_source);
784
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000785 source = String::Concat(source, right);
786 right = String::NewExternal(
787 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
788 source = String::Concat(source, right);
789 Local<Script> script = Script::Compile(source);
790 Local<Value> value = script->Run();
791 CHECK(value->IsNumber());
792 CHECK_EQ(68, value->Int32Value());
793 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000794 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000795 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
796 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000797}
798
799
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800THREADED_TEST(GlobalProperties) {
801 v8::HandleScope scope;
802 LocalContext env;
803 v8::Handle<v8::Object> global = env->Global();
804 global->Set(v8_str("pi"), v8_num(3.1415926));
805 Local<Value> pi = global->Get(v8_str("pi"));
806 CHECK_EQ(3.1415926, pi->NumberValue());
807}
808
809
810static v8::Handle<Value> handle_call(const v8::Arguments& args) {
811 ApiTestFuzzer::Fuzz();
812 return v8_num(102);
813}
814
815
816static v8::Handle<Value> construct_call(const v8::Arguments& args) {
817 ApiTestFuzzer::Fuzz();
818 args.This()->Set(v8_str("x"), v8_num(1));
819 args.This()->Set(v8_str("y"), v8_num(2));
820 return args.This();
821}
822
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000823static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
824 ApiTestFuzzer::Fuzz();
825 return v8_num(239);
826}
827
828
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000829THREADED_TEST(FunctionTemplate) {
830 v8::HandleScope scope;
831 LocalContext env;
832 {
833 Local<v8::FunctionTemplate> fun_templ =
834 v8::FunctionTemplate::New(handle_call);
835 Local<Function> fun = fun_templ->GetFunction();
836 env->Global()->Set(v8_str("obj"), fun);
837 Local<Script> script = v8_compile("obj()");
838 CHECK_EQ(102, script->Run()->Int32Value());
839 }
840 // Use SetCallHandler to initialize a function template, should work like the
841 // previous one.
842 {
843 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
844 fun_templ->SetCallHandler(handle_call);
845 Local<Function> fun = fun_templ->GetFunction();
846 env->Global()->Set(v8_str("obj"), fun);
847 Local<Script> script = v8_compile("obj()");
848 CHECK_EQ(102, script->Run()->Int32Value());
849 }
850 // Test constructor calls.
851 {
852 Local<v8::FunctionTemplate> fun_templ =
853 v8::FunctionTemplate::New(construct_call);
854 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000855 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000856 Local<Function> fun = fun_templ->GetFunction();
857 env->Global()->Set(v8_str("obj"), fun);
858 Local<Script> script = v8_compile("var s = new obj(); s.x");
859 CHECK_EQ(1, script->Run()->Int32Value());
860
861 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
862 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000863
864 result = v8_compile("(new obj()).m")->Run();
865 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000866 }
867}
868
869
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000870THREADED_TEST(FunctionTemplateSetLength) {
871 v8::HandleScope scope;
872 LocalContext env;
873 {
874 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
875 handle_call, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
876 Local<Function> fun = fun_templ->GetFunction();
877 env->Global()->Set(v8_str("obj"), fun);
878 Local<Script> script = v8_compile("obj.length");
879 CHECK_EQ(23, script->Run()->Int32Value());
880 }
881 {
882 Local<v8::FunctionTemplate> fun_templ =
883 v8::FunctionTemplate::New(handle_call);
884 fun_templ->SetLength(22);
885 Local<Function> fun = fun_templ->GetFunction();
886 env->Global()->Set(v8_str("obj"), fun);
887 Local<Script> script = v8_compile("obj.length");
888 CHECK_EQ(22, script->Run()->Int32Value());
889 }
890 {
891 // Without setting length it defaults to 0.
892 Local<v8::FunctionTemplate> fun_templ =
893 v8::FunctionTemplate::New(handle_call);
894 Local<Function> fun = fun_templ->GetFunction();
895 env->Global()->Set(v8_str("obj"), fun);
896 Local<Script> script = v8_compile("obj.length");
897 CHECK_EQ(0, script->Run()->Int32Value());
898 }
899}
900
901
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000902static void* expected_ptr;
903static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000904 void* ptr = v8::External::Cast(*args.Data())->Value();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000905 CHECK_EQ(expected_ptr, ptr);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000906 return v8::True();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000907}
908
909
910static void TestExternalPointerWrapping() {
911 v8::HandleScope scope;
912 LocalContext env;
913
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000914 v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000915
916 v8::Handle<v8::Object> obj = v8::Object::New();
917 obj->Set(v8_str("func"),
918 v8::FunctionTemplate::New(callback, data)->GetFunction());
919 env->Global()->Set(v8_str("obj"), obj);
920
921 CHECK(CompileRun(
922 "function foo() {\n"
923 " for (var i = 0; i < 13; i++) obj.func();\n"
924 "}\n"
925 "foo(), true")->BooleanValue());
926}
927
928
929THREADED_TEST(ExternalWrap) {
930 // Check heap allocated object.
931 int* ptr = new int;
932 expected_ptr = ptr;
933 TestExternalPointerWrapping();
934 delete ptr;
935
936 // Check stack allocated object.
937 int foo;
938 expected_ptr = &foo;
939 TestExternalPointerWrapping();
940
941 // Check not aligned addresses.
942 const int n = 100;
943 char* s = new char[n];
944 for (int i = 0; i < n; i++) {
945 expected_ptr = s + i;
946 TestExternalPointerWrapping();
947 }
948
949 delete[] s;
950
951 // Check several invalid addresses.
952 expected_ptr = reinterpret_cast<void*>(1);
953 TestExternalPointerWrapping();
954
955 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
956 TestExternalPointerWrapping();
957
958 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
959 TestExternalPointerWrapping();
960
961#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000962 // Check a value with a leading 1 bit in x64 Smi encoding.
963 expected_ptr = reinterpret_cast<void*>(0x400000000);
964 TestExternalPointerWrapping();
965
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000966 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
967 TestExternalPointerWrapping();
968
969 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
970 TestExternalPointerWrapping();
971#endif
972}
973
974
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000975THREADED_TEST(FindInstanceInPrototypeChain) {
976 v8::HandleScope scope;
977 LocalContext env;
978
979 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
980 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
981 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
982 derived->Inherit(base);
983
984 Local<v8::Function> base_function = base->GetFunction();
985 Local<v8::Function> derived_function = derived->GetFunction();
986 Local<v8::Function> other_function = other->GetFunction();
987
988 Local<v8::Object> base_instance = base_function->NewInstance();
989 Local<v8::Object> derived_instance = derived_function->NewInstance();
990 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
991 Local<v8::Object> other_instance = other_function->NewInstance();
992 derived_instance2->Set(v8_str("__proto__"), derived_instance);
993 other_instance->Set(v8_str("__proto__"), derived_instance2);
994
995 // base_instance is only an instance of base.
996 CHECK_EQ(base_instance,
997 base_instance->FindInstanceInPrototypeChain(base));
998 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
999 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1000
1001 // derived_instance is an instance of base and derived.
1002 CHECK_EQ(derived_instance,
1003 derived_instance->FindInstanceInPrototypeChain(base));
1004 CHECK_EQ(derived_instance,
1005 derived_instance->FindInstanceInPrototypeChain(derived));
1006 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1007
1008 // other_instance is an instance of other and its immediate
1009 // prototype derived_instance2 is an instance of base and derived.
1010 // Note, derived_instance is an instance of base and derived too,
1011 // but it comes after derived_instance2 in the prototype chain of
1012 // other_instance.
1013 CHECK_EQ(derived_instance2,
1014 other_instance->FindInstanceInPrototypeChain(base));
1015 CHECK_EQ(derived_instance2,
1016 other_instance->FindInstanceInPrototypeChain(derived));
1017 CHECK_EQ(other_instance,
1018 other_instance->FindInstanceInPrototypeChain(other));
1019}
1020
1021
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001022THREADED_TEST(TinyInteger) {
1023 v8::HandleScope scope;
1024 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001025 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1026
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001027 int32_t value = 239;
1028 Local<v8::Integer> value_obj = v8::Integer::New(value);
1029 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001030
1031 value_obj = v8::Integer::New(value, isolate);
1032 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001033}
1034
1035
1036THREADED_TEST(BigSmiInteger) {
1037 v8::HandleScope scope;
1038 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001039 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1040
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001041 int32_t value = i::Smi::kMaxValue;
1042 // We cannot add one to a Smi::kMaxValue without wrapping.
1043 if (i::kSmiValueSize < 32) {
1044 CHECK(i::Smi::IsValid(value));
1045 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001046
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001047 Local<v8::Integer> value_obj = v8::Integer::New(value);
1048 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001049
1050 value_obj = v8::Integer::New(value, isolate);
1051 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001052 }
1053}
1054
1055
1056THREADED_TEST(BigInteger) {
1057 v8::HandleScope scope;
1058 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001059 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1060
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001061 // We cannot add one to a Smi::kMaxValue without wrapping.
1062 if (i::kSmiValueSize < 32) {
1063 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1064 // The code will not be run in that case, due to the "if" guard.
1065 int32_t value =
1066 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1067 CHECK(value > i::Smi::kMaxValue);
1068 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001069
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001070 Local<v8::Integer> value_obj = v8::Integer::New(value);
1071 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001072
1073 value_obj = v8::Integer::New(value, isolate);
1074 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001075 }
1076}
1077
1078
1079THREADED_TEST(TinyUnsignedInteger) {
1080 v8::HandleScope scope;
1081 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001082 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1083
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001084 uint32_t value = 239;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001085
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001086 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1087 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001088
1089 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1090 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001091}
1092
1093
1094THREADED_TEST(BigUnsignedSmiInteger) {
1095 v8::HandleScope scope;
1096 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001097 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1098
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001099 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1100 CHECK(i::Smi::IsValid(value));
1101 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001102
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001103 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1104 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001105
1106 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1107 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001108}
1109
1110
1111THREADED_TEST(BigUnsignedInteger) {
1112 v8::HandleScope scope;
1113 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001114 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1115
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001116 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1117 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1118 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001119
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001120 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1121 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001122
1123 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1124 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001125}
1126
1127
1128THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1129 v8::HandleScope scope;
1130 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001131 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1132
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001133 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1134 uint32_t value = INT32_MAX_AS_UINT + 1;
1135 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001136
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001137 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1138 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001139
1140 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1141 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001142}
1143
1144
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001145THREADED_TEST(IsNativeError) {
1146 v8::HandleScope scope;
1147 LocalContext env;
1148 v8::Handle<Value> syntax_error = CompileRun(
1149 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1150 CHECK(syntax_error->IsNativeError());
1151 v8::Handle<Value> not_error = CompileRun("{a:42}");
1152 CHECK(!not_error->IsNativeError());
1153 v8::Handle<Value> not_object = CompileRun("42");
1154 CHECK(!not_object->IsNativeError());
1155}
1156
1157
1158THREADED_TEST(StringObject) {
1159 v8::HandleScope scope;
1160 LocalContext env;
1161 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1162 CHECK(boxed_string->IsStringObject());
1163 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1164 CHECK(!unboxed_string->IsStringObject());
1165 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1166 CHECK(!boxed_not_string->IsStringObject());
1167 v8::Handle<Value> not_object = CompileRun("0");
1168 CHECK(!not_object->IsStringObject());
1169 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1170 CHECK(!as_boxed.IsEmpty());
1171 Local<v8::String> the_string = as_boxed->StringValue();
1172 CHECK(!the_string.IsEmpty());
1173 ExpectObject("\"test\"", the_string);
1174 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1175 CHECK(new_boxed_string->IsStringObject());
1176 as_boxed = new_boxed_string.As<v8::StringObject>();
1177 the_string = as_boxed->StringValue();
1178 CHECK(!the_string.IsEmpty());
1179 ExpectObject("\"test\"", the_string);
1180}
1181
1182
1183THREADED_TEST(NumberObject) {
1184 v8::HandleScope scope;
1185 LocalContext env;
1186 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1187 CHECK(boxed_number->IsNumberObject());
1188 v8::Handle<Value> unboxed_number = CompileRun("42");
1189 CHECK(!unboxed_number->IsNumberObject());
1190 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1191 CHECK(!boxed_not_number->IsNumberObject());
1192 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1193 CHECK(!as_boxed.IsEmpty());
1194 double the_number = as_boxed->NumberValue();
1195 CHECK_EQ(42.0, the_number);
1196 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1197 CHECK(new_boxed_number->IsNumberObject());
1198 as_boxed = new_boxed_number.As<v8::NumberObject>();
1199 the_number = as_boxed->NumberValue();
1200 CHECK_EQ(43.0, the_number);
1201}
1202
1203
1204THREADED_TEST(BooleanObject) {
1205 v8::HandleScope scope;
1206 LocalContext env;
1207 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1208 CHECK(boxed_boolean->IsBooleanObject());
1209 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1210 CHECK(!unboxed_boolean->IsBooleanObject());
1211 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1212 CHECK(!boxed_not_boolean->IsBooleanObject());
1213 v8::Handle<v8::BooleanObject> as_boxed =
1214 boxed_boolean.As<v8::BooleanObject>();
1215 CHECK(!as_boxed.IsEmpty());
1216 bool the_boolean = as_boxed->BooleanValue();
1217 CHECK_EQ(true, the_boolean);
1218 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1219 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1220 CHECK(boxed_true->IsBooleanObject());
1221 CHECK(boxed_false->IsBooleanObject());
1222 as_boxed = boxed_true.As<v8::BooleanObject>();
1223 CHECK_EQ(true, as_boxed->BooleanValue());
1224 as_boxed = boxed_false.As<v8::BooleanObject>();
1225 CHECK_EQ(false, as_boxed->BooleanValue());
1226}
1227
1228
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001229THREADED_TEST(Number) {
1230 v8::HandleScope scope;
1231 LocalContext env;
1232 double PI = 3.1415926;
1233 Local<v8::Number> pi_obj = v8::Number::New(PI);
1234 CHECK_EQ(PI, pi_obj->NumberValue());
1235}
1236
1237
1238THREADED_TEST(ToNumber) {
1239 v8::HandleScope scope;
1240 LocalContext env;
1241 Local<String> str = v8_str("3.1415926");
1242 CHECK_EQ(3.1415926, str->NumberValue());
1243 v8::Handle<v8::Boolean> t = v8::True();
1244 CHECK_EQ(1.0, t->NumberValue());
1245 v8::Handle<v8::Boolean> f = v8::False();
1246 CHECK_EQ(0.0, f->NumberValue());
1247}
1248
1249
1250THREADED_TEST(Date) {
1251 v8::HandleScope scope;
1252 LocalContext env;
1253 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001254 Local<Value> date = v8::Date::New(PI);
1255 CHECK_EQ(3.0, date->NumberValue());
1256 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1257 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001258}
1259
1260
1261THREADED_TEST(Boolean) {
1262 v8::HandleScope scope;
1263 LocalContext env;
1264 v8::Handle<v8::Boolean> t = v8::True();
1265 CHECK(t->Value());
1266 v8::Handle<v8::Boolean> f = v8::False();
1267 CHECK(!f->Value());
1268 v8::Handle<v8::Primitive> u = v8::Undefined();
1269 CHECK(!u->BooleanValue());
1270 v8::Handle<v8::Primitive> n = v8::Null();
1271 CHECK(!n->BooleanValue());
1272 v8::Handle<String> str1 = v8_str("");
1273 CHECK(!str1->BooleanValue());
1274 v8::Handle<String> str2 = v8_str("x");
1275 CHECK(str2->BooleanValue());
1276 CHECK(!v8::Number::New(0)->BooleanValue());
1277 CHECK(v8::Number::New(-1)->BooleanValue());
1278 CHECK(v8::Number::New(1)->BooleanValue());
1279 CHECK(v8::Number::New(42)->BooleanValue());
1280 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1281}
1282
1283
1284static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1285 ApiTestFuzzer::Fuzz();
1286 return v8_num(13.4);
1287}
1288
1289
1290static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1291 ApiTestFuzzer::Fuzz();
1292 return v8_num(876);
1293}
1294
1295
1296THREADED_TEST(GlobalPrototype) {
1297 v8::HandleScope scope;
1298 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1299 func_templ->PrototypeTemplate()->Set(
1300 "dummy",
1301 v8::FunctionTemplate::New(DummyCallHandler));
1302 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1303 templ->Set("x", v8_num(200));
1304 templ->SetAccessor(v8_str("m"), GetM);
1305 LocalContext env(0, templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001306 v8::Handle<Script> script(v8_compile("dummy()"));
1307 v8::Handle<Value> result(script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001308 CHECK_EQ(13.4, result->NumberValue());
1309 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1310 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1311}
1312
1313
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001314THREADED_TEST(ObjectTemplate) {
1315 v8::HandleScope scope;
1316 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1317 templ1->Set("x", v8_num(10));
1318 templ1->Set("y", v8_num(13));
1319 LocalContext env;
1320 Local<v8::Object> instance1 = templ1->NewInstance();
1321 env->Global()->Set(v8_str("p"), instance1);
1322 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1323 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1324 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1325 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1326 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1327 templ2->Set("a", v8_num(12));
1328 templ2->Set("b", templ1);
1329 Local<v8::Object> instance2 = templ2->NewInstance();
1330 env->Global()->Set(v8_str("q"), instance2);
1331 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1332 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1333 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1334 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1335}
1336
1337
1338static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1339 ApiTestFuzzer::Fuzz();
1340 return v8_num(17.2);
1341}
1342
1343
1344static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1345 ApiTestFuzzer::Fuzz();
1346 return v8_num(15.2);
1347}
1348
1349
1350THREADED_TEST(DescriptorInheritance) {
1351 v8::HandleScope scope;
1352 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1353 super->PrototypeTemplate()->Set("flabby",
1354 v8::FunctionTemplate::New(GetFlabby));
1355 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1356
1357 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1358
1359 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1360 base1->Inherit(super);
1361 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1362
1363 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1364 base2->Inherit(super);
1365 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1366
1367 LocalContext env;
1368
1369 env->Global()->Set(v8_str("s"), super->GetFunction());
1370 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1371 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1372
1373 // Checks right __proto__ chain.
1374 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1375 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1376
1377 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1378
1379 // Instance accessor should not be visible on function object or its prototype
1380 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1381 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1382 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1383
1384 env->Global()->Set(v8_str("obj"),
1385 base1->GetFunction()->NewInstance());
1386 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1387 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1388 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1389 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1390 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1391
1392 env->Global()->Set(v8_str("obj2"),
1393 base2->GetFunction()->NewInstance());
1394 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1395 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1396 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1397 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1398 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1399
1400 // base1 and base2 cannot cross reference to each's prototype
1401 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1402 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1403}
1404
1405
1406int echo_named_call_count;
1407
1408
1409static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1410 const AccessorInfo& info) {
1411 ApiTestFuzzer::Fuzz();
1412 CHECK_EQ(v8_str("data"), info.Data());
1413 echo_named_call_count++;
1414 return name;
1415}
1416
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417// Helper functions for Interceptor/Accessor interaction tests
1418
1419Handle<Value> SimpleAccessorGetter(Local<String> name,
1420 const AccessorInfo& info) {
1421 Handle<Object> self = info.This();
1422 return self->Get(String::Concat(v8_str("accessor_"), name));
1423}
1424
1425void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1426 const AccessorInfo& info) {
1427 Handle<Object> self = info.This();
1428 self->Set(String::Concat(v8_str("accessor_"), name), value);
1429}
1430
1431Handle<Value> EmptyInterceptorGetter(Local<String> name,
1432 const AccessorInfo& info) {
1433 return Handle<Value>();
1434}
1435
1436Handle<Value> EmptyInterceptorSetter(Local<String> name,
1437 Local<Value> value,
1438 const AccessorInfo& info) {
1439 return Handle<Value>();
1440}
1441
1442Handle<Value> InterceptorGetter(Local<String> name,
1443 const AccessorInfo& info) {
1444 // Intercept names that start with 'interceptor_'.
1445 String::AsciiValue ascii(name);
1446 char* name_str = *ascii;
1447 char prefix[] = "interceptor_";
1448 int i;
1449 for (i = 0; name_str[i] && prefix[i]; ++i) {
1450 if (name_str[i] != prefix[i]) return Handle<Value>();
1451 }
1452 Handle<Object> self = info.This();
1453 return self->GetHiddenValue(v8_str(name_str + i));
1454}
1455
1456Handle<Value> InterceptorSetter(Local<String> name,
1457 Local<Value> value,
1458 const AccessorInfo& info) {
1459 // Intercept accesses that set certain integer values.
1460 if (value->IsInt32() && value->Int32Value() < 10000) {
1461 Handle<Object> self = info.This();
1462 self->SetHiddenValue(name, value);
1463 return value;
1464 }
1465 return Handle<Value>();
1466}
1467
1468void AddAccessor(Handle<FunctionTemplate> templ,
1469 Handle<String> name,
1470 v8::AccessorGetter getter,
1471 v8::AccessorSetter setter) {
1472 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1473}
1474
1475void AddInterceptor(Handle<FunctionTemplate> templ,
1476 v8::NamedPropertyGetter getter,
1477 v8::NamedPropertySetter setter) {
1478 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1479}
1480
1481THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1482 v8::HandleScope scope;
1483 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1484 Handle<FunctionTemplate> child = FunctionTemplate::New();
1485 child->Inherit(parent);
1486 AddAccessor(parent, v8_str("age"),
1487 SimpleAccessorGetter, SimpleAccessorSetter);
1488 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1489 LocalContext env;
1490 env->Global()->Set(v8_str("Child"), child->GetFunction());
1491 CompileRun("var child = new Child;"
1492 "child.age = 10;");
1493 ExpectBoolean("child.hasOwnProperty('age')", false);
1494 ExpectInt32("child.age", 10);
1495 ExpectInt32("child.accessor_age", 10);
1496}
1497
1498THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1499 v8::HandleScope scope;
1500 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1501 Handle<FunctionTemplate> child = FunctionTemplate::New();
1502 child->Inherit(parent);
1503 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1504 LocalContext env;
1505 env->Global()->Set(v8_str("Child"), child->GetFunction());
1506 CompileRun("var child = new Child;"
1507 "var parent = child.__proto__;"
1508 "Object.defineProperty(parent, 'age', "
1509 " {get: function(){ return this.accessor_age; }, "
1510 " set: function(v){ this.accessor_age = v; }, "
1511 " enumerable: true, configurable: true});"
1512 "child.age = 10;");
1513 ExpectBoolean("child.hasOwnProperty('age')", false);
1514 ExpectInt32("child.age", 10);
1515 ExpectInt32("child.accessor_age", 10);
1516}
1517
1518THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1519 v8::HandleScope scope;
1520 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1521 Handle<FunctionTemplate> child = FunctionTemplate::New();
1522 child->Inherit(parent);
1523 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1524 LocalContext env;
1525 env->Global()->Set(v8_str("Child"), child->GetFunction());
1526 CompileRun("var child = new Child;"
1527 "var parent = child.__proto__;"
1528 "parent.name = 'Alice';");
1529 ExpectBoolean("child.hasOwnProperty('name')", false);
1530 ExpectString("child.name", "Alice");
1531 CompileRun("child.name = 'Bob';");
1532 ExpectString("child.name", "Bob");
1533 ExpectBoolean("child.hasOwnProperty('name')", true);
1534 ExpectString("parent.name", "Alice");
1535}
1536
1537THREADED_TEST(SwitchFromInterceptorToAccessor) {
1538 v8::HandleScope scope;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001539 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1540 AddAccessor(templ, v8_str("age"),
1541 SimpleAccessorGetter, SimpleAccessorSetter);
1542 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1543 LocalContext env;
1544 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1545 CompileRun("var obj = new Obj;"
1546 "function setAge(i){ obj.age = i; };"
1547 "for(var i = 0; i <= 10000; i++) setAge(i);");
1548 // All i < 10000 go to the interceptor.
1549 ExpectInt32("obj.interceptor_age", 9999);
1550 // The last i goes to the accessor.
1551 ExpectInt32("obj.accessor_age", 10000);
1552}
1553
1554THREADED_TEST(SwitchFromAccessorToInterceptor) {
1555 v8::HandleScope scope;
1556 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1557 AddAccessor(templ, v8_str("age"),
1558 SimpleAccessorGetter, SimpleAccessorSetter);
1559 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1560 LocalContext env;
1561 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1562 CompileRun("var obj = new Obj;"
1563 "function setAge(i){ obj.age = i; };"
1564 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1565 // All i >= 10000 go to the accessor.
1566 ExpectInt32("obj.accessor_age", 10000);
1567 // The last i goes to the interceptor.
1568 ExpectInt32("obj.interceptor_age", 9999);
1569}
1570
1571THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1572 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1574 Handle<FunctionTemplate> child = FunctionTemplate::New();
1575 child->Inherit(parent);
1576 AddAccessor(parent, v8_str("age"),
1577 SimpleAccessorGetter, SimpleAccessorSetter);
1578 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1579 LocalContext env;
1580 env->Global()->Set(v8_str("Child"), child->GetFunction());
1581 CompileRun("var child = new Child;"
1582 "function setAge(i){ child.age = i; };"
1583 "for(var i = 0; i <= 10000; i++) setAge(i);");
1584 // All i < 10000 go to the interceptor.
1585 ExpectInt32("child.interceptor_age", 9999);
1586 // The last i goes to the accessor.
1587 ExpectInt32("child.accessor_age", 10000);
1588}
1589
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001590THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 v8::HandleScope scope;
1592 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1593 Handle<FunctionTemplate> child = FunctionTemplate::New();
1594 child->Inherit(parent);
1595 AddAccessor(parent, v8_str("age"),
1596 SimpleAccessorGetter, SimpleAccessorSetter);
1597 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1598 LocalContext env;
1599 env->Global()->Set(v8_str("Child"), child->GetFunction());
1600 CompileRun("var child = new Child;"
1601 "function setAge(i){ child.age = i; };"
1602 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1603 // All i >= 10000 go to the accessor.
1604 ExpectInt32("child.accessor_age", 10000);
1605 // The last i goes to the interceptor.
1606 ExpectInt32("child.interceptor_age", 9999);
1607}
1608
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001609THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1610 v8::HandleScope scope;
1611 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1612 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1613 LocalContext env;
1614 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1615 CompileRun("var obj = new Obj;"
1616 "function setter(i) { this.accessor_age = i; };"
1617 "function getter() { return this.accessor_age; };"
1618 "function setAge(i) { obj.age = i; };"
1619 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1620 "for(var i = 0; i <= 10000; i++) setAge(i);");
1621 // All i < 10000 go to the interceptor.
1622 ExpectInt32("obj.interceptor_age", 9999);
1623 // The last i goes to the JavaScript accessor.
1624 ExpectInt32("obj.accessor_age", 10000);
1625 // The installed JavaScript getter is still intact.
1626 // This last part is a regression test for issue 1651 and relies on the fact
1627 // that both interceptor and accessor are being installed on the same object.
1628 ExpectInt32("obj.age", 10000);
1629 ExpectBoolean("obj.hasOwnProperty('age')", true);
1630 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1631}
1632
1633THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1634 v8::HandleScope scope;
1635 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1636 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1637 LocalContext env;
1638 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1639 CompileRun("var obj = new Obj;"
1640 "function setter(i) { this.accessor_age = i; };"
1641 "function getter() { return this.accessor_age; };"
1642 "function setAge(i) { obj.age = i; };"
1643 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1644 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1645 // All i >= 10000 go to the accessor.
1646 ExpectInt32("obj.accessor_age", 10000);
1647 // The last i goes to the interceptor.
1648 ExpectInt32("obj.interceptor_age", 9999);
1649 // The installed JavaScript getter is still intact.
1650 // This last part is a regression test for issue 1651 and relies on the fact
1651 // that both interceptor and accessor are being installed on the same object.
1652 ExpectInt32("obj.age", 10000);
1653 ExpectBoolean("obj.hasOwnProperty('age')", true);
1654 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1655}
1656
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001657THREADED_TEST(SwitchFromInterceptorToProperty) {
1658 v8::HandleScope scope;
1659 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1660 Handle<FunctionTemplate> child = FunctionTemplate::New();
1661 child->Inherit(parent);
1662 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1663 LocalContext env;
1664 env->Global()->Set(v8_str("Child"), child->GetFunction());
1665 CompileRun("var child = new Child;"
1666 "function setAge(i){ child.age = i; };"
1667 "for(var i = 0; i <= 10000; i++) setAge(i);");
1668 // All i < 10000 go to the interceptor.
1669 ExpectInt32("child.interceptor_age", 9999);
1670 // The last i goes to child's own property.
1671 ExpectInt32("child.age", 10000);
1672}
1673
1674THREADED_TEST(SwitchFromPropertyToInterceptor) {
1675 v8::HandleScope scope;
1676 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1677 Handle<FunctionTemplate> child = FunctionTemplate::New();
1678 child->Inherit(parent);
1679 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1680 LocalContext env;
1681 env->Global()->Set(v8_str("Child"), child->GetFunction());
1682 CompileRun("var child = new Child;"
1683 "function setAge(i){ child.age = i; };"
1684 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1685 // All i >= 10000 go to child's own property.
1686 ExpectInt32("child.age", 10000);
1687 // The last i goes to the interceptor.
1688 ExpectInt32("child.interceptor_age", 9999);
1689}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001690
1691THREADED_TEST(NamedPropertyHandlerGetter) {
1692 echo_named_call_count = 0;
1693 v8::HandleScope scope;
1694 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1695 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1696 0, 0, 0, 0,
1697 v8_str("data"));
1698 LocalContext env;
1699 env->Global()->Set(v8_str("obj"),
1700 templ->GetFunction()->NewInstance());
1701 CHECK_EQ(echo_named_call_count, 0);
1702 v8_compile("obj.x")->Run();
1703 CHECK_EQ(echo_named_call_count, 1);
1704 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1705 v8::Handle<Value> str = CompileRun(code);
1706 String::AsciiValue value(str);
1707 CHECK_EQ(*value, "oddlepoddle");
1708 // Check default behavior
1709 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1710 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1711 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1712}
1713
1714
1715int echo_indexed_call_count = 0;
1716
1717
1718static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1719 const AccessorInfo& info) {
1720 ApiTestFuzzer::Fuzz();
1721 CHECK_EQ(v8_num(637), info.Data());
1722 echo_indexed_call_count++;
1723 return v8_num(index);
1724}
1725
1726
1727THREADED_TEST(IndexedPropertyHandlerGetter) {
1728 v8::HandleScope scope;
1729 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1730 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1731 0, 0, 0, 0,
1732 v8_num(637));
1733 LocalContext env;
1734 env->Global()->Set(v8_str("obj"),
1735 templ->GetFunction()->NewInstance());
1736 Local<Script> script = v8_compile("obj[900]");
1737 CHECK_EQ(script->Run()->Int32Value(), 900);
1738}
1739
1740
1741v8::Handle<v8::Object> bottom;
1742
1743static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1744 uint32_t index,
1745 const AccessorInfo& info) {
1746 ApiTestFuzzer::Fuzz();
1747 CHECK(info.This()->Equals(bottom));
1748 return v8::Handle<Value>();
1749}
1750
1751static v8::Handle<Value> CheckThisNamedPropertyHandler(
1752 Local<String> name,
1753 const AccessorInfo& info) {
1754 ApiTestFuzzer::Fuzz();
1755 CHECK(info.This()->Equals(bottom));
1756 return v8::Handle<Value>();
1757}
1758
1759
1760v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1761 Local<Value> value,
1762 const AccessorInfo& info) {
1763 ApiTestFuzzer::Fuzz();
1764 CHECK(info.This()->Equals(bottom));
1765 return v8::Handle<Value>();
1766}
1767
1768
1769v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1770 Local<Value> value,
1771 const AccessorInfo& info) {
1772 ApiTestFuzzer::Fuzz();
1773 CHECK(info.This()->Equals(bottom));
1774 return v8::Handle<Value>();
1775}
1776
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001777v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001778 uint32_t index,
1779 const AccessorInfo& info) {
1780 ApiTestFuzzer::Fuzz();
1781 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001782 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001783}
1784
1785
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001786v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001787 const AccessorInfo& info) {
1788 ApiTestFuzzer::Fuzz();
1789 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001790 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001791}
1792
1793
1794v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1795 uint32_t index,
1796 const AccessorInfo& info) {
1797 ApiTestFuzzer::Fuzz();
1798 CHECK(info.This()->Equals(bottom));
1799 return v8::Handle<v8::Boolean>();
1800}
1801
1802
1803v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1804 Local<String> property,
1805 const AccessorInfo& info) {
1806 ApiTestFuzzer::Fuzz();
1807 CHECK(info.This()->Equals(bottom));
1808 return v8::Handle<v8::Boolean>();
1809}
1810
1811
1812v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1813 const AccessorInfo& info) {
1814 ApiTestFuzzer::Fuzz();
1815 CHECK(info.This()->Equals(bottom));
1816 return v8::Handle<v8::Array>();
1817}
1818
1819
1820v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1821 const AccessorInfo& info) {
1822 ApiTestFuzzer::Fuzz();
1823 CHECK(info.This()->Equals(bottom));
1824 return v8::Handle<v8::Array>();
1825}
1826
1827
1828THREADED_TEST(PropertyHandlerInPrototype) {
1829 v8::HandleScope scope;
1830 LocalContext env;
1831
1832 // Set up a prototype chain with three interceptors.
1833 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1834 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1835 CheckThisIndexedPropertyHandler,
1836 CheckThisIndexedPropertySetter,
1837 CheckThisIndexedPropertyQuery,
1838 CheckThisIndexedPropertyDeleter,
1839 CheckThisIndexedPropertyEnumerator);
1840
1841 templ->InstanceTemplate()->SetNamedPropertyHandler(
1842 CheckThisNamedPropertyHandler,
1843 CheckThisNamedPropertySetter,
1844 CheckThisNamedPropertyQuery,
1845 CheckThisNamedPropertyDeleter,
1846 CheckThisNamedPropertyEnumerator);
1847
1848 bottom = templ->GetFunction()->NewInstance();
1849 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1850 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1851
1852 bottom->Set(v8_str("__proto__"), middle);
1853 middle->Set(v8_str("__proto__"), top);
1854 env->Global()->Set(v8_str("obj"), bottom);
1855
1856 // Indexed and named get.
1857 Script::Compile(v8_str("obj[0]"))->Run();
1858 Script::Compile(v8_str("obj.x"))->Run();
1859
1860 // Indexed and named set.
1861 Script::Compile(v8_str("obj[1] = 42"))->Run();
1862 Script::Compile(v8_str("obj.y = 42"))->Run();
1863
1864 // Indexed and named query.
1865 Script::Compile(v8_str("0 in obj"))->Run();
1866 Script::Compile(v8_str("'x' in obj"))->Run();
1867
1868 // Indexed and named deleter.
1869 Script::Compile(v8_str("delete obj[0]"))->Run();
1870 Script::Compile(v8_str("delete obj.x"))->Run();
1871
1872 // Enumerators.
1873 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1874}
1875
1876
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001877static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1878 const AccessorInfo& info) {
1879 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 if (v8_str("pre")->Equals(key)) {
1881 return v8_str("PrePropertyHandler: pre");
1882 }
1883 return v8::Handle<String>();
1884}
1885
1886
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001887static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1888 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001889 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001890 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001891 }
1892
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001893 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001894}
1895
1896
1897THREADED_TEST(PrePropertyHandler) {
1898 v8::HandleScope scope;
1899 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1900 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1901 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001902 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001903 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001904 Script::Compile(v8_str(
1905 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1906 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1907 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1908 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1909 CHECK_EQ(v8_str("Object: on"), result_on);
1910 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1911 CHECK(result_post.IsEmpty());
1912}
1913
1914
ager@chromium.org870a0b62008-11-04 11:43:05 +00001915THREADED_TEST(UndefinedIsNotEnumerable) {
1916 v8::HandleScope scope;
1917 LocalContext env;
1918 v8::Handle<Value> result = Script::Compile(v8_str(
1919 "this.propertyIsEnumerable(undefined)"))->Run();
1920 CHECK(result->IsFalse());
1921}
1922
1923
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001925static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001926
1927
1928static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1929 ApiTestFuzzer::Fuzz();
1930 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1931 if (depth == kTargetRecursionDepth) return v8::Undefined();
1932 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1933 return call_recursively_script->Run();
1934}
1935
1936
1937static v8::Handle<Value> CallFunctionRecursivelyCall(
1938 const v8::Arguments& args) {
1939 ApiTestFuzzer::Fuzz();
1940 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1941 if (depth == kTargetRecursionDepth) {
1942 printf("[depth = %d]\n", depth);
1943 return v8::Undefined();
1944 }
1945 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1946 v8::Handle<Value> function =
1947 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001948 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001949}
1950
1951
1952THREADED_TEST(DeepCrossLanguageRecursion) {
1953 v8::HandleScope scope;
1954 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1955 global->Set(v8_str("callScriptRecursively"),
1956 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1957 global->Set(v8_str("callFunctionRecursively"),
1958 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1959 LocalContext env(NULL, global);
1960
1961 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1962 call_recursively_script = v8_compile("callScriptRecursively()");
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001963 call_recursively_script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001964 call_recursively_script = v8::Handle<Script>();
1965
1966 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1967 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1968}
1969
1970
1971static v8::Handle<Value>
1972 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1973 ApiTestFuzzer::Fuzz();
1974 return v8::ThrowException(key);
1975}
1976
1977
1978static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1979 Local<Value>,
1980 const AccessorInfo&) {
1981 v8::ThrowException(key);
1982 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1983}
1984
1985
1986THREADED_TEST(CallbackExceptionRegression) {
1987 v8::HandleScope scope;
1988 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1989 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1990 ThrowingPropertyHandlerSet);
1991 LocalContext env;
1992 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1993 v8::Handle<Value> otto = Script::Compile(v8_str(
1994 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1995 CHECK_EQ(v8_str("otto"), otto);
1996 v8::Handle<Value> netto = Script::Compile(v8_str(
1997 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1998 CHECK_EQ(v8_str("netto"), netto);
1999}
2000
2001
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002002THREADED_TEST(FunctionPrototype) {
2003 v8::HandleScope scope;
2004 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2005 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2006 LocalContext env;
2007 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2008 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2009 CHECK_EQ(script->Run()->Int32Value(), 321);
2010}
2011
2012
2013THREADED_TEST(InternalFields) {
2014 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002015 LocalContext env;
2016
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002017 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2018 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2019 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002020 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2021 CHECK_EQ(1, obj->InternalFieldCount());
2022 CHECK(obj->GetInternalField(0)->IsUndefined());
2023 obj->SetInternalField(0, v8_num(17));
2024 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2025}
2026
2027
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002028THREADED_TEST(GlobalObjectInternalFields) {
2029 v8::HandleScope scope;
2030 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2031 global_template->SetInternalFieldCount(1);
2032 LocalContext env(NULL, global_template);
2033 v8::Handle<v8::Object> global_proxy = env->Global();
2034 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2035 CHECK_EQ(1, global->InternalFieldCount());
2036 CHECK(global->GetInternalField(0)->IsUndefined());
2037 global->SetInternalField(0, v8_num(17));
2038 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2039}
2040
2041
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002042static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2043 void* value) {
2044 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002045 obj->SetAlignedPointerInInternalField(0, value);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002046 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002047 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002048}
2049
2050
2051THREADED_TEST(InternalFieldsAlignedPointers) {
2052 v8::HandleScope scope;
2053 LocalContext env;
2054
2055 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2056 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2057 instance_templ->SetInternalFieldCount(1);
2058 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2059 CHECK_EQ(1, obj->InternalFieldCount());
2060
2061 CheckAlignedPointerInInternalField(obj, NULL);
2062
2063 int* heap_allocated = new int[100];
2064 CheckAlignedPointerInInternalField(obj, heap_allocated);
2065 delete[] heap_allocated;
2066
2067 int stack_allocated[100];
2068 CheckAlignedPointerInInternalField(obj, stack_allocated);
2069
2070 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2071 CheckAlignedPointerInInternalField(obj, huge);
2072}
2073
2074
2075static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2076 int index,
2077 void* value) {
2078 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2079 (*env)->SetAlignedPointerInEmbedderData(index, value);
2080 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2081 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2082}
2083
2084
2085static void* AlignedTestPointer(int i) {
2086 return reinterpret_cast<void*>(i * 1234);
2087}
2088
2089
2090THREADED_TEST(EmbedderDataAlignedPointers) {
2091 v8::HandleScope scope;
2092 LocalContext env;
2093
2094 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2095
2096 int* heap_allocated = new int[100];
2097 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2098 delete[] heap_allocated;
2099
2100 int stack_allocated[100];
2101 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2102
2103 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2104 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2105
2106 // Test growing of the embedder data's backing store.
2107 for (int i = 0; i < 100; i++) {
2108 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2109 }
2110 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2111 for (int i = 0; i < 100; i++) {
2112 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2113 }
2114}
2115
2116
2117static void CheckEmbedderData(LocalContext* env,
2118 int index,
2119 v8::Handle<Value> data) {
2120 (*env)->SetEmbedderData(index, data);
2121 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2122}
2123
2124THREADED_TEST(EmbedderData) {
2125 v8::HandleScope scope;
2126 LocalContext env;
2127
2128 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2129 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2130 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2131 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2132}
2133
2134
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002135THREADED_TEST(IdentityHash) {
2136 v8::HandleScope scope;
2137 LocalContext env;
2138
2139 // Ensure that the test starts with an fresh heap to test whether the hash
2140 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002141 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002142 Local<v8::Object> obj = v8::Object::New();
2143 int hash = obj->GetIdentityHash();
2144 int hash1 = obj->GetIdentityHash();
2145 CHECK_EQ(hash, hash1);
2146 int hash2 = v8::Object::New()->GetIdentityHash();
2147 // Since the identity hash is essentially a random number two consecutive
2148 // objects should not be assigned the same hash code. If the test below fails
2149 // the random number generator should be evaluated.
2150 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002151 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002152 int hash3 = v8::Object::New()->GetIdentityHash();
2153 // Make sure that the identity hash is not based on the initial address of
2154 // the object alone. If the test below fails the random number generator
2155 // should be evaluated.
2156 CHECK_NE(hash, hash3);
2157 int hash4 = obj->GetIdentityHash();
2158 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002159
2160 // Check identity hashes behaviour in the presence of JS accessors.
2161 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2162 {
2163 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2164 Local<v8::Object> o1 = v8::Object::New();
2165 Local<v8::Object> o2 = v8::Object::New();
2166 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2167 }
2168 {
2169 CompileRun(
2170 "function cnst() { return 42; };\n"
2171 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2172 Local<v8::Object> o1 = v8::Object::New();
2173 Local<v8::Object> o2 = v8::Object::New();
2174 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2175 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002176}
2177
2178
2179THREADED_TEST(HiddenProperties) {
2180 v8::HandleScope scope;
2181 LocalContext env;
2182
2183 v8::Local<v8::Object> obj = v8::Object::New();
2184 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2185 v8::Local<v8::String> empty = v8_str("");
2186 v8::Local<v8::String> prop_name = v8_str("prop_name");
2187
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002188 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002189
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00002190 // Make sure delete of a non-existent hidden value works
2191 CHECK(obj->DeleteHiddenValue(key));
2192
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002193 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2194 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2195 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2196 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2197
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002198 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002199
2200 // Make sure we do not find the hidden property.
2201 CHECK(!obj->Has(empty));
2202 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2203 CHECK(obj->Get(empty)->IsUndefined());
2204 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2205 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2206 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2207 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2208
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002209 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002210
2211 // Add another property and delete it afterwards to force the object in
2212 // slow case.
2213 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2214 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2215 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2216 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2217 CHECK(obj->Delete(prop_name));
2218 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2219
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002220 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002221
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002222 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2223 CHECK(obj->GetHiddenValue(key).IsEmpty());
2224
2225 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002226 CHECK(obj->DeleteHiddenValue(key));
2227 CHECK(obj->GetHiddenValue(key).IsEmpty());
2228}
2229
2230
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002231THREADED_TEST(Regress97784) {
2232 // Regression test for crbug.com/97784
2233 // Messing with the Object.prototype should not have effect on
2234 // hidden properties.
2235 v8::HandleScope scope;
2236 LocalContext env;
2237
2238 v8::Local<v8::Object> obj = v8::Object::New();
2239 v8::Local<v8::String> key = v8_str("hidden");
2240
2241 CompileRun(
2242 "set_called = false;"
2243 "Object.defineProperty("
2244 " Object.prototype,"
2245 " 'hidden',"
2246 " {get: function() { return 45; },"
2247 " set: function() { set_called = true; }})");
2248
2249 CHECK(obj->GetHiddenValue(key).IsEmpty());
2250 // Make sure that the getter and setter from Object.prototype is not invoked.
2251 // If it did we would have full access to the hidden properties in
2252 // the accessor.
2253 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2254 ExpectFalse("set_called");
2255 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2256}
2257
2258
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002259static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002260static v8::Handle<Value> InterceptorForHiddenProperties(
2261 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002262 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002263 return v8::Handle<Value>();
2264}
2265
2266
2267THREADED_TEST(HiddenPropertiesWithInterceptors) {
2268 v8::HandleScope scope;
2269 LocalContext context;
2270
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002271 interceptor_for_hidden_properties_called = false;
2272
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002273 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2274
2275 // Associate an interceptor with an object and start setting hidden values.
2276 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2277 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2278 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2279 Local<v8::Function> function = fun_templ->GetFunction();
2280 Local<v8::Object> obj = function->NewInstance();
2281 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2282 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002283 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002284}
2285
2286
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002287THREADED_TEST(External) {
2288 v8::HandleScope scope;
2289 int x = 3;
2290 Local<v8::External> ext = v8::External::New(&x);
2291 LocalContext env;
2292 env->Global()->Set(v8_str("ext"), ext);
2293 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002294 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002295 int* ptr = static_cast<int*>(reext->Value());
2296 CHECK_EQ(x, 3);
2297 *ptr = 10;
2298 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299
2300 // Make sure unaligned pointers are wrapped properly.
2301 char* data = i::StrDup("0123456789");
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002302 Local<v8::Value> zero = v8::External::New(&data[0]);
2303 Local<v8::Value> one = v8::External::New(&data[1]);
2304 Local<v8::Value> two = v8::External::New(&data[2]);
2305 Local<v8::Value> three = v8::External::New(&data[3]);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002307 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002308 CHECK_EQ('0', *char_ptr);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002309 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002310 CHECK_EQ('1', *char_ptr);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002311 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002312 CHECK_EQ('2', *char_ptr);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002313 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 CHECK_EQ('3', *char_ptr);
2315 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002316}
2317
2318
2319THREADED_TEST(GlobalHandle) {
2320 v8::Persistent<String> global;
2321 {
2322 v8::HandleScope scope;
2323 Local<String> str = v8_str("str");
2324 global = v8::Persistent<String>::New(str);
2325 }
2326 CHECK_EQ(global->Length(), 3);
2327 global.Dispose();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002328
2329 {
2330 v8::HandleScope scope;
2331 Local<String> str = v8_str("str");
2332 global = v8::Persistent<String>::New(str);
2333 }
2334 CHECK_EQ(global->Length(), 3);
2335 global.Dispose(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002336}
2337
2338
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002339THREADED_TEST(LocalHandle) {
2340 v8::HandleScope scope;
2341 v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
2342 CHECK_EQ(local->Length(), 3);
2343
2344 local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str"));
2345 CHECK_EQ(local->Length(), 3);
2346}
2347
2348
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002349class WeakCallCounter {
2350 public:
2351 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2352 int id() { return id_; }
2353 void increment() { number_of_weak_calls_++; }
2354 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2355 private:
2356 int id_;
2357 int number_of_weak_calls_;
2358};
2359
2360
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002361static void WeakPointerCallback(Persistent<Value> handle, void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002362 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2363 CHECK_EQ(1234, counter->id());
2364 counter->increment();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002365 handle.Dispose();
2366}
2367
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002368
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002369THREADED_TEST(ApiObjectGroups) {
2370 HandleScope scope;
2371 LocalContext env;
2372
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002373 Persistent<Object> g1s1;
2374 Persistent<Object> g1s2;
2375 Persistent<Object> g1c1;
2376 Persistent<Object> g2s1;
2377 Persistent<Object> g2s2;
2378 Persistent<Object> g2c1;
2379
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002380 WeakCallCounter counter(1234);
2381
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002382 {
2383 HandleScope scope;
2384 g1s1 = Persistent<Object>::New(Object::New());
2385 g1s2 = Persistent<Object>::New(Object::New());
2386 g1c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002387 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2388 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2389 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002390
2391 g2s1 = Persistent<Object>::New(Object::New());
2392 g2s2 = Persistent<Object>::New(Object::New());
2393 g2c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002394 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2395 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2396 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002397 }
2398
2399 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2400
2401 // Connect group 1 and 2, make a cycle.
2402 CHECK(g1s2->Set(0, g2s2));
2403 CHECK(g2s1->Set(0, g1s1));
2404
2405 {
2406 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2407 Persistent<Value> g1_children[] = { g1c1 };
2408 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2409 Persistent<Value> g2_children[] = { g2c1 };
2410 V8::AddObjectGroup(g1_objects, 2);
2411 V8::AddImplicitReferences(g1s1, g1_children, 1);
2412 V8::AddObjectGroup(g2_objects, 2);
2413 V8::AddImplicitReferences(g2s2, g2_children, 1);
2414 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002415 // Do a single full GC, ensure incremental marking is stopped.
2416 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002417
2418 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002419 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002420
2421 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002422 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002423 // But make children strong roots---all the objects (except for children)
2424 // should be collectable now.
2425 g1c1.ClearWeak();
2426 g2c1.ClearWeak();
2427
2428 // Groups are deleted, rebuild groups.
2429 {
2430 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2431 Persistent<Value> g1_children[] = { g1c1 };
2432 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2433 Persistent<Value> g2_children[] = { g2c1 };
2434 V8::AddObjectGroup(g1_objects, 2);
2435 V8::AddImplicitReferences(g1s1, g1_children, 1);
2436 V8::AddObjectGroup(g2_objects, 2);
2437 V8::AddImplicitReferences(g2s2, g2_children, 1);
2438 }
2439
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002440 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002441
2442 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002443 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002444
2445 // And now make children weak again and collect them.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002446 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2447 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002448
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002449 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002450 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002451}
2452
2453
2454THREADED_TEST(ApiObjectGroupsCycle) {
2455 HandleScope scope;
2456 LocalContext env;
2457
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002458 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002459
2460 Persistent<Object> g1s1;
2461 Persistent<Object> g1s2;
2462 Persistent<Object> g2s1;
2463 Persistent<Object> g2s2;
2464 Persistent<Object> g3s1;
2465 Persistent<Object> g3s2;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002466 Persistent<Object> g4s1;
2467 Persistent<Object> g4s2;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002468
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002469 v8::Isolate* isolate = v8::Isolate::GetCurrent();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002470 {
2471 HandleScope scope;
2472 g1s1 = Persistent<Object>::New(Object::New());
2473 g1s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002474 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2475 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002476 CHECK(g1s1.IsWeak());
2477 CHECK(g1s2.IsWeak());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002478
2479 g2s1 = Persistent<Object>::New(Object::New());
2480 g2s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002481 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2482 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002483 CHECK(g2s1.IsWeak());
2484 CHECK(g2s2.IsWeak());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002485
2486 g3s1 = Persistent<Object>::New(Object::New());
2487 g3s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002488 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2489 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002490 CHECK(g3s1.IsWeak());
2491 CHECK(g3s2.IsWeak());
2492
2493 g4s1 = Persistent<Object>::New(Object::New());
2494 g4s2 = Persistent<Object>::New(Object::New());
2495 g4s1.MakeWeak(isolate,
2496 reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2497 g4s2.MakeWeak(isolate,
2498 reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2499 CHECK(g4s1.IsWeak(isolate));
2500 CHECK(g4s2.IsWeak(isolate));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002501 }
2502
2503 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2504
2505 // Connect groups. We're building the following cycle:
2506 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2507 // groups.
2508 {
2509 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2510 Persistent<Value> g1_children[] = { g2s1 };
2511 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2512 Persistent<Value> g2_children[] = { g3s1 };
2513 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002514 Persistent<Value> g3_children[] = { g4s1 };
2515 Persistent<Value> g4_objects[] = { g4s1, g4s2 };
2516 Persistent<Value> g4_children[] = { g1s1 };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002517 V8::AddObjectGroup(g1_objects, 2);
2518 V8::AddImplicitReferences(g1s1, g1_children, 1);
2519 V8::AddObjectGroup(g2_objects, 2);
2520 V8::AddImplicitReferences(g2s1, g2_children, 1);
2521 V8::AddObjectGroup(g3_objects, 2);
2522 V8::AddImplicitReferences(g3s1, g3_children, 1);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002523 V8::AddObjectGroup(isolate, g4_objects, 2);
2524 V8::AddImplicitReferences(g4s1, g4_children, 1);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002525 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002526 // Do a single full GC
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002527 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002528
2529 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002530 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002531
2532 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002533 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002534
2535 // Groups are deleted, rebuild groups.
2536 {
2537 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2538 Persistent<Value> g1_children[] = { g2s1 };
2539 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2540 Persistent<Value> g2_children[] = { g3s1 };
2541 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002542 Persistent<Value> g3_children[] = { g4s1 };
2543 Persistent<Value> g4_objects[] = { g4s1, g4s2 };
2544 Persistent<Value> g4_children[] = { g1s1 };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002545 V8::AddObjectGroup(g1_objects, 2);
2546 V8::AddImplicitReferences(g1s1, g1_children, 1);
2547 V8::AddObjectGroup(g2_objects, 2);
2548 V8::AddImplicitReferences(g2s1, g2_children, 1);
2549 V8::AddObjectGroup(g3_objects, 2);
2550 V8::AddImplicitReferences(g3s1, g3_children, 1);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002551 V8::AddObjectGroup(g4_objects, 2);
2552 V8::AddImplicitReferences(g4s1, g4_children, 1);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002553 }
2554
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002555 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002556
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002557 // All objects should be gone. 9 global handles in total.
2558 CHECK_EQ(9, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002559}
2560
2561
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002562// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
2563// on the buildbots, so was made non-threaded for the time being.
2564TEST(ApiObjectGroupsCycleForScavenger) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002565 i::FLAG_stress_compaction = false;
2566 i::FLAG_gc_global = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002567 HandleScope scope;
2568 LocalContext env;
2569
2570 WeakCallCounter counter(1234);
2571
2572 Persistent<Object> g1s1;
2573 Persistent<Object> g1s2;
2574 Persistent<Object> g2s1;
2575 Persistent<Object> g2s2;
2576 Persistent<Object> g3s1;
2577 Persistent<Object> g3s2;
2578
2579 {
2580 HandleScope scope;
2581 g1s1 = Persistent<Object>::New(Object::New());
2582 g1s2 = Persistent<Object>::New(Object::New());
2583 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2584 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2585
2586 g2s1 = Persistent<Object>::New(Object::New());
2587 g2s2 = Persistent<Object>::New(Object::New());
2588 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2589 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2590
2591 g3s1 = Persistent<Object>::New(Object::New());
2592 g3s2 = Persistent<Object>::New(Object::New());
2593 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2594 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2595 }
2596
2597 // Make a root.
2598 Persistent<Object> root = Persistent<Object>::New(g1s1);
2599 root.MarkPartiallyDependent();
2600
2601 // Connect groups. We're building the following cycle:
2602 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2603 // groups.
2604 {
2605 g1s1.MarkPartiallyDependent();
2606 g1s2.MarkPartiallyDependent();
2607 g2s1.MarkPartiallyDependent();
2608 g2s2.MarkPartiallyDependent();
2609 g3s1.MarkPartiallyDependent();
2610 g3s2.MarkPartiallyDependent();
2611 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2612 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2613 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2614 V8::AddObjectGroup(g1_objects, 2);
2615 g1s1->Set(v8_str("x"), g2s1);
2616 V8::AddObjectGroup(g2_objects, 2);
2617 g2s1->Set(v8_str("x"), g3s1);
2618 V8::AddObjectGroup(g3_objects, 2);
2619 g3s1->Set(v8_str("x"), g1s1);
2620 }
2621
2622 HEAP->CollectGarbage(i::NEW_SPACE);
2623
2624 // All objects should be alive.
2625 CHECK_EQ(0, counter.NumberOfWeakCalls());
2626
2627 // Weaken the root.
2628 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2629 root.MarkPartiallyDependent();
2630
2631 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2632 // Groups are deleted, rebuild groups.
2633 {
2634 g1s1.MarkPartiallyDependent(isolate);
2635 g1s2.MarkPartiallyDependent(isolate);
2636 g2s1.MarkPartiallyDependent(isolate);
2637 g2s2.MarkPartiallyDependent(isolate);
2638 g3s1.MarkPartiallyDependent(isolate);
2639 g3s2.MarkPartiallyDependent(isolate);
2640 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2641 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2642 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2643 V8::AddObjectGroup(g1_objects, 2);
2644 g1s1->Set(v8_str("x"), g2s1);
2645 V8::AddObjectGroup(g2_objects, 2);
2646 g2s1->Set(v8_str("x"), g3s1);
2647 V8::AddObjectGroup(g3_objects, 2);
2648 g3s1->Set(v8_str("x"), g1s1);
2649 }
2650
2651 HEAP->CollectGarbage(i::NEW_SPACE);
2652
2653 // All objects should be gone. 7 global handles in total.
2654 CHECK_EQ(7, counter.NumberOfWeakCalls());
2655}
2656
2657
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002658THREADED_TEST(ScriptException) {
2659 v8::HandleScope scope;
2660 LocalContext env;
2661 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2662 v8::TryCatch try_catch;
2663 Local<Value> result = script->Run();
2664 CHECK(result.IsEmpty());
2665 CHECK(try_catch.HasCaught());
2666 String::AsciiValue exception_value(try_catch.Exception());
2667 CHECK_EQ(*exception_value, "panama!");
2668}
2669
2670
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002671TEST(TryCatchCustomException) {
2672 v8::HandleScope scope;
2673 LocalContext env;
2674 v8::TryCatch try_catch;
2675 CompileRun("function CustomError() { this.a = 'b'; }"
2676 "(function f() { throw new CustomError(); })();");
2677 CHECK(try_catch.HasCaught());
2678 CHECK(try_catch.Exception()->ToObject()->
2679 Get(v8_str("a"))->Equals(v8_str("b")));
2680}
2681
2682
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002683bool message_received;
2684
2685
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002686static void check_message_0(v8::Handle<v8::Message> message,
2687 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002688 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002689 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002690 message_received = true;
2691}
2692
2693
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002694THREADED_TEST(MessageHandler0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002695 message_received = false;
2696 v8::HandleScope scope;
2697 CHECK(!message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002698 v8::V8::AddMessageListener(check_message_0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002699 LocalContext context;
2700 v8::ScriptOrigin origin =
2701 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002702 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2703 &origin);
2704 script->SetData(v8_str("7.56"));
2705 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002706 CHECK(message_received);
2707 // clear out the message listener
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002708 v8::V8::RemoveMessageListeners(check_message_0);
2709}
2710
2711
2712static void check_message_1(v8::Handle<v8::Message> message,
2713 v8::Handle<Value> data) {
2714 CHECK(data->IsNumber());
2715 CHECK_EQ(1337, data->Int32Value());
2716 message_received = true;
2717}
2718
2719
2720TEST(MessageHandler1) {
2721 message_received = false;
2722 v8::HandleScope scope;
2723 CHECK(!message_received);
2724 v8::V8::AddMessageListener(check_message_1);
2725 LocalContext context;
2726 CompileRun("throw 1337;");
2727 CHECK(message_received);
2728 // clear out the message listener
2729 v8::V8::RemoveMessageListeners(check_message_1);
2730}
2731
2732
2733static void check_message_2(v8::Handle<v8::Message> message,
2734 v8::Handle<Value> data) {
2735 LocalContext context;
2736 CHECK(data->IsObject());
2737 v8::Local<v8::Value> hidden_property =
2738 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2739 CHECK(v8_str("hidden value")->Equals(hidden_property));
2740 message_received = true;
2741}
2742
2743
2744TEST(MessageHandler2) {
2745 message_received = false;
2746 v8::HandleScope scope;
2747 CHECK(!message_received);
2748 v8::V8::AddMessageListener(check_message_2);
2749 LocalContext context;
2750 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2751 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2752 v8_str("hidden value"));
2753 context->Global()->Set(v8_str("error"), error);
2754 CompileRun("throw error;");
2755 CHECK(message_received);
2756 // clear out the message listener
2757 v8::V8::RemoveMessageListeners(check_message_2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002758}
2759
2760
2761THREADED_TEST(GetSetProperty) {
2762 v8::HandleScope scope;
2763 LocalContext context;
2764 context->Global()->Set(v8_str("foo"), v8_num(14));
2765 context->Global()->Set(v8_str("12"), v8_num(92));
2766 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2767 context->Global()->Set(v8_num(13), v8_num(56));
2768 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2769 CHECK_EQ(14, foo->Int32Value());
2770 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2771 CHECK_EQ(92, twelve->Int32Value());
2772 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2773 CHECK_EQ(32, sixteen->Int32Value());
2774 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2775 CHECK_EQ(56, thirteen->Int32Value());
2776 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2777 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2778 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2779 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2780 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2781 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2782 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2783 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2784 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2785}
2786
2787
2788THREADED_TEST(PropertyAttributes) {
2789 v8::HandleScope scope;
2790 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002791 // none
2792 Local<String> prop = v8_str("none");
2793 context->Global()->Set(prop, v8_num(7));
2794 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002795 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002796 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002797 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2798 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002799 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002800 Script::Compile(v8_str("read_only = 9"))->Run();
2801 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2802 context->Global()->Set(prop, v8_num(10));
2803 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2804 // dont-delete
2805 prop = v8_str("dont_delete");
2806 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2807 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2808 Script::Compile(v8_str("delete dont_delete"))->Run();
2809 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002810 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2811 // dont-enum
2812 prop = v8_str("dont_enum");
2813 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2814 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2815 // absent
2816 prop = v8_str("absent");
2817 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2818 Local<Value> fake_prop = v8_num(1);
2819 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2820 // exception
2821 TryCatch try_catch;
2822 Local<Value> exception =
2823 CompileRun("({ toString: function() { throw 'exception';} })");
2824 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2825 CHECK(try_catch.HasCaught());
2826 String::AsciiValue exception_value(try_catch.Exception());
2827 CHECK_EQ("exception", *exception_value);
2828 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002829}
2830
2831
2832THREADED_TEST(Array) {
2833 v8::HandleScope scope;
2834 LocalContext context;
2835 Local<v8::Array> array = v8::Array::New();
2836 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002837 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002838 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002839 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002840 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002841 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002842 CHECK_EQ(3, array->Length());
2843 CHECK(!array->Has(0));
2844 CHECK(!array->Has(1));
2845 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002846 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002847 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002848 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002849 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002850 CHECK_EQ(1, arr->Get(0)->Int32Value());
2851 CHECK_EQ(2, arr->Get(1)->Int32Value());
2852 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002853 array = v8::Array::New(27);
2854 CHECK_EQ(27, array->Length());
2855 array = v8::Array::New(-27);
2856 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002857}
2858
2859
2860v8::Handle<Value> HandleF(const v8::Arguments& args) {
2861 v8::HandleScope scope;
2862 ApiTestFuzzer::Fuzz();
2863 Local<v8::Array> result = v8::Array::New(args.Length());
2864 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002865 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002866 return scope.Close(result);
2867}
2868
2869
2870THREADED_TEST(Vector) {
2871 v8::HandleScope scope;
2872 Local<ObjectTemplate> global = ObjectTemplate::New();
2873 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2874 LocalContext context(0, global);
2875
2876 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002877 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002878 CHECK_EQ(0, a0->Length());
2879
2880 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002881 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002882 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002883 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002884
2885 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002886 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002887 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002888 CHECK_EQ(12, a2->Get(0)->Int32Value());
2889 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002890
2891 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002892 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002893 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002894 CHECK_EQ(14, a3->Get(0)->Int32Value());
2895 CHECK_EQ(15, a3->Get(1)->Int32Value());
2896 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002897
2898 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002899 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002900 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002901 CHECK_EQ(17, a4->Get(0)->Int32Value());
2902 CHECK_EQ(18, a4->Get(1)->Int32Value());
2903 CHECK_EQ(19, a4->Get(2)->Int32Value());
2904 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002905}
2906
2907
2908THREADED_TEST(FunctionCall) {
2909 v8::HandleScope scope;
2910 LocalContext context;
2911 CompileRun(
2912 "function Foo() {"
2913 " var result = [];"
2914 " for (var i = 0; i < arguments.length; i++) {"
2915 " result.push(arguments[i]);"
2916 " }"
2917 " return result;"
2918 "}");
2919 Local<Function> Foo =
2920 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2921
2922 v8::Handle<Value>* args0 = NULL;
2923 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2924 CHECK_EQ(0, a0->Length());
2925
2926 v8::Handle<Value> args1[] = { v8_num(1.1) };
2927 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2928 CHECK_EQ(1, a1->Length());
2929 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2930
2931 v8::Handle<Value> args2[] = { v8_num(2.2),
2932 v8_num(3.3) };
2933 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2934 CHECK_EQ(2, a2->Length());
2935 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2936 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2937
2938 v8::Handle<Value> args3[] = { v8_num(4.4),
2939 v8_num(5.5),
2940 v8_num(6.6) };
2941 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2942 CHECK_EQ(3, a3->Length());
2943 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2944 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2945 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2946
2947 v8::Handle<Value> args4[] = { v8_num(7.7),
2948 v8_num(8.8),
2949 v8_num(9.9),
2950 v8_num(10.11) };
2951 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2952 CHECK_EQ(4, a4->Length());
2953 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2954 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2955 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2956 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2957}
2958
2959
2960static const char* js_code_causing_out_of_memory =
2961 "var a = new Array(); while(true) a.push(a);";
2962
2963
2964// These tests run for a long time and prevent us from running tests
2965// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002966TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002967 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002968 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002969 // Set heap limits.
2970 static const int K = 1024;
2971 v8::ResourceConstraints constraints;
2972 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002973 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002974 v8::SetResourceConstraints(&constraints);
2975
2976 // Execute a script that causes out of memory.
2977 v8::HandleScope scope;
2978 LocalContext context;
2979 v8::V8::IgnoreOutOfMemoryException();
2980 Local<Script> script =
2981 Script::Compile(String::New(js_code_causing_out_of_memory));
2982 Local<Value> result = script->Run();
2983
2984 // Check for out of memory state.
2985 CHECK(result.IsEmpty());
2986 CHECK(context->HasOutOfMemoryException());
2987}
2988
2989
2990v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2991 ApiTestFuzzer::Fuzz();
2992
2993 v8::HandleScope scope;
2994 LocalContext context;
2995 Local<Script> script =
2996 Script::Compile(String::New(js_code_causing_out_of_memory));
2997 Local<Value> result = script->Run();
2998
2999 // Check for out of memory state.
3000 CHECK(result.IsEmpty());
3001 CHECK(context->HasOutOfMemoryException());
3002
3003 return result;
3004}
3005
3006
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003007TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003008 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003009 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003010 // Set heap limits.
3011 static const int K = 1024;
3012 v8::ResourceConstraints constraints;
3013 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003014 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003015 v8::SetResourceConstraints(&constraints);
3016
3017 v8::HandleScope scope;
3018 Local<ObjectTemplate> templ = ObjectTemplate::New();
3019 templ->Set(v8_str("ProvokeOutOfMemory"),
3020 v8::FunctionTemplate::New(ProvokeOutOfMemory));
3021 LocalContext context(0, templ);
3022 v8::V8::IgnoreOutOfMemoryException();
3023 Local<Value> result = CompileRun(
3024 "var thrown = false;"
3025 "try {"
3026 " ProvokeOutOfMemory();"
3027 "} catch (e) {"
3028 " thrown = true;"
3029 "}");
3030 // Check for out of memory state.
3031 CHECK(result.IsEmpty());
3032 CHECK(context->HasOutOfMemoryException());
3033}
3034
3035
3036TEST(HugeConsStringOutOfMemory) {
3037 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003038 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003039 // Set heap limits.
3040 static const int K = 1024;
3041 v8::ResourceConstraints constraints;
3042 constraints.set_max_young_space_size(256 * K);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003043 constraints.set_max_old_space_size(3 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003044 v8::SetResourceConstraints(&constraints);
3045
3046 // Execute a script that causes out of memory.
3047 v8::V8::IgnoreOutOfMemoryException();
3048
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003049 v8::HandleScope scope;
3050 LocalContext context;
3051
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003052 // Build huge string. This should fail with out of memory exception.
3053 Local<Value> result = CompileRun(
3054 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003055 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003056
3057 // Check for out of memory state.
3058 CHECK(result.IsEmpty());
3059 CHECK(context->HasOutOfMemoryException());
3060}
3061
3062
3063THREADED_TEST(ConstructCall) {
3064 v8::HandleScope scope;
3065 LocalContext context;
3066 CompileRun(
3067 "function Foo() {"
3068 " var result = [];"
3069 " for (var i = 0; i < arguments.length; i++) {"
3070 " result.push(arguments[i]);"
3071 " }"
3072 " return result;"
3073 "}");
3074 Local<Function> Foo =
3075 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3076
3077 v8::Handle<Value>* args0 = NULL;
3078 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
3079 CHECK_EQ(0, a0->Length());
3080
3081 v8::Handle<Value> args1[] = { v8_num(1.1) };
3082 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
3083 CHECK_EQ(1, a1->Length());
3084 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3085
3086 v8::Handle<Value> args2[] = { v8_num(2.2),
3087 v8_num(3.3) };
3088 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
3089 CHECK_EQ(2, a2->Length());
3090 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3091 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3092
3093 v8::Handle<Value> args3[] = { v8_num(4.4),
3094 v8_num(5.5),
3095 v8_num(6.6) };
3096 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
3097 CHECK_EQ(3, a3->Length());
3098 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3099 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3100 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3101
3102 v8::Handle<Value> args4[] = { v8_num(7.7),
3103 v8_num(8.8),
3104 v8_num(9.9),
3105 v8_num(10.11) };
3106 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
3107 CHECK_EQ(4, a4->Length());
3108 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3109 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3110 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3111 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3112}
3113
3114
3115static void CheckUncle(v8::TryCatch* try_catch) {
3116 CHECK(try_catch->HasCaught());
3117 String::AsciiValue str_value(try_catch->Exception());
3118 CHECK_EQ(*str_value, "uncle?");
3119 try_catch->Reset();
3120}
3121
3122
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003123THREADED_TEST(ConversionNumber) {
3124 v8::HandleScope scope;
3125 LocalContext env;
3126 // Very large number.
3127 CompileRun("var obj = Math.pow(2,32) * 1237;");
3128 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3129 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
3130 CHECK_EQ(0, obj->ToInt32()->Value());
3131 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
3132 // Large number.
3133 CompileRun("var obj = -1234567890123;");
3134 obj = env->Global()->Get(v8_str("obj"));
3135 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
3136 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
3137 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
3138 // Small positive integer.
3139 CompileRun("var obj = 42;");
3140 obj = env->Global()->Get(v8_str("obj"));
3141 CHECK_EQ(42.0, obj->ToNumber()->Value());
3142 CHECK_EQ(42, obj->ToInt32()->Value());
3143 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3144 // Negative integer.
3145 CompileRun("var obj = -37;");
3146 obj = env->Global()->Get(v8_str("obj"));
3147 CHECK_EQ(-37.0, obj->ToNumber()->Value());
3148 CHECK_EQ(-37, obj->ToInt32()->Value());
3149 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
3150 // Positive non-int32 integer.
3151 CompileRun("var obj = 0x81234567;");
3152 obj = env->Global()->Get(v8_str("obj"));
3153 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
3154 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
3155 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
3156 // Fraction.
3157 CompileRun("var obj = 42.3;");
3158 obj = env->Global()->Get(v8_str("obj"));
3159 CHECK_EQ(42.3, obj->ToNumber()->Value());
3160 CHECK_EQ(42, obj->ToInt32()->Value());
3161 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3162 // Large negative fraction.
3163 CompileRun("var obj = -5726623061.75;");
3164 obj = env->Global()->Get(v8_str("obj"));
3165 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
3166 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
3167 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
3168}
3169
3170
3171THREADED_TEST(isNumberType) {
3172 v8::HandleScope scope;
3173 LocalContext env;
3174 // Very large number.
3175 CompileRun("var obj = Math.pow(2,32) * 1237;");
3176 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3177 CHECK(!obj->IsInt32());
3178 CHECK(!obj->IsUint32());
3179 // Large negative number.
3180 CompileRun("var obj = -1234567890123;");
3181 obj = env->Global()->Get(v8_str("obj"));
3182 CHECK(!obj->IsInt32());
3183 CHECK(!obj->IsUint32());
3184 // Small positive integer.
3185 CompileRun("var obj = 42;");
3186 obj = env->Global()->Get(v8_str("obj"));
3187 CHECK(obj->IsInt32());
3188 CHECK(obj->IsUint32());
3189 // Negative integer.
3190 CompileRun("var obj = -37;");
3191 obj = env->Global()->Get(v8_str("obj"));
3192 CHECK(obj->IsInt32());
3193 CHECK(!obj->IsUint32());
3194 // Positive non-int32 integer.
3195 CompileRun("var obj = 0x81234567;");
3196 obj = env->Global()->Get(v8_str("obj"));
3197 CHECK(!obj->IsInt32());
3198 CHECK(obj->IsUint32());
3199 // Fraction.
3200 CompileRun("var obj = 42.3;");
3201 obj = env->Global()->Get(v8_str("obj"));
3202 CHECK(!obj->IsInt32());
3203 CHECK(!obj->IsUint32());
3204 // Large negative fraction.
3205 CompileRun("var obj = -5726623061.75;");
3206 obj = env->Global()->Get(v8_str("obj"));
3207 CHECK(!obj->IsInt32());
3208 CHECK(!obj->IsUint32());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003209 // Positive zero
3210 CompileRun("var obj = 0.0;");
3211 obj = env->Global()->Get(v8_str("obj"));
3212 CHECK(obj->IsInt32());
3213 CHECK(obj->IsUint32());
3214 // Positive zero
3215 CompileRun("var obj = -0.0;");
3216 obj = env->Global()->Get(v8_str("obj"));
3217 CHECK(!obj->IsInt32());
3218 CHECK(!obj->IsUint32());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003219}
3220
3221
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003222THREADED_TEST(ConversionException) {
3223 v8::HandleScope scope;
3224 LocalContext env;
3225 CompileRun(
3226 "function TestClass() { };"
3227 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3228 "var obj = new TestClass();");
3229 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3230
3231 v8::TryCatch try_catch;
3232
3233 Local<Value> to_string_result = obj->ToString();
3234 CHECK(to_string_result.IsEmpty());
3235 CheckUncle(&try_catch);
3236
3237 Local<Value> to_number_result = obj->ToNumber();
3238 CHECK(to_number_result.IsEmpty());
3239 CheckUncle(&try_catch);
3240
3241 Local<Value> to_integer_result = obj->ToInteger();
3242 CHECK(to_integer_result.IsEmpty());
3243 CheckUncle(&try_catch);
3244
3245 Local<Value> to_uint32_result = obj->ToUint32();
3246 CHECK(to_uint32_result.IsEmpty());
3247 CheckUncle(&try_catch);
3248
3249 Local<Value> to_int32_result = obj->ToInt32();
3250 CHECK(to_int32_result.IsEmpty());
3251 CheckUncle(&try_catch);
3252
3253 Local<Value> to_object_result = v8::Undefined()->ToObject();
3254 CHECK(to_object_result.IsEmpty());
3255 CHECK(try_catch.HasCaught());
3256 try_catch.Reset();
3257
3258 int32_t int32_value = obj->Int32Value();
3259 CHECK_EQ(0, int32_value);
3260 CheckUncle(&try_catch);
3261
3262 uint32_t uint32_value = obj->Uint32Value();
3263 CHECK_EQ(0, uint32_value);
3264 CheckUncle(&try_catch);
3265
3266 double number_value = obj->NumberValue();
3267 CHECK_NE(0, IsNaN(number_value));
3268 CheckUncle(&try_catch);
3269
3270 int64_t integer_value = obj->IntegerValue();
3271 CHECK_EQ(0.0, static_cast<double>(integer_value));
3272 CheckUncle(&try_catch);
3273}
3274
3275
3276v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3277 ApiTestFuzzer::Fuzz();
3278 return v8::ThrowException(v8_str("konto"));
3279}
3280
3281
ager@chromium.org8bb60582008-12-11 12:02:20 +00003282v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003283 if (args.Length() < 1) return v8::False();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003284 v8::HandleScope scope;
3285 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00003286 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3287 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003288 return v8::Boolean::New(try_catch.HasCaught());
3289}
3290
3291
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003292THREADED_TEST(APICatch) {
3293 v8::HandleScope scope;
3294 Local<ObjectTemplate> templ = ObjectTemplate::New();
3295 templ->Set(v8_str("ThrowFromC"),
3296 v8::FunctionTemplate::New(ThrowFromC));
3297 LocalContext context(0, templ);
3298 CompileRun(
3299 "var thrown = false;"
3300 "try {"
3301 " ThrowFromC();"
3302 "} catch (e) {"
3303 " thrown = true;"
3304 "}");
3305 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3306 CHECK(thrown->BooleanValue());
3307}
3308
3309
ager@chromium.org8bb60582008-12-11 12:02:20 +00003310THREADED_TEST(APIThrowTryCatch) {
3311 v8::HandleScope scope;
3312 Local<ObjectTemplate> templ = ObjectTemplate::New();
3313 templ->Set(v8_str("ThrowFromC"),
3314 v8::FunctionTemplate::New(ThrowFromC));
3315 LocalContext context(0, templ);
3316 v8::TryCatch try_catch;
3317 CompileRun("ThrowFromC();");
3318 CHECK(try_catch.HasCaught());
3319}
3320
3321
3322// Test that a try-finally block doesn't shadow a try-catch block
3323// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003324//
3325// BUG(271): Some of the exception propagation does not work on the
3326// ARM simulator because the simulator separates the C++ stack and the
3327// JS stack. This test therefore fails on the simulator. The test is
3328// not threaded to allow the threading tests to run on the simulator.
3329TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00003330 v8::HandleScope scope;
3331 Local<ObjectTemplate> templ = ObjectTemplate::New();
3332 templ->Set(v8_str("CCatcher"),
3333 v8::FunctionTemplate::New(CCatcher));
3334 LocalContext context(0, templ);
3335 Local<Value> result = CompileRun("try {"
3336 " try {"
3337 " CCatcher('throw 7;');"
3338 " } finally {"
3339 " }"
3340 "} catch (e) {"
3341 "}");
3342 CHECK(result->IsTrue());
3343}
3344
3345
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003346static void check_reference_error_message(
3347 v8::Handle<v8::Message> message,
3348 v8::Handle<v8::Value> data) {
3349 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3350 CHECK(message->Get()->Equals(v8_str(reference_error)));
3351}
3352
3353
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003354static v8::Handle<Value> Fail(const v8::Arguments& args) {
3355 ApiTestFuzzer::Fuzz();
3356 CHECK(false);
3357 return v8::Undefined();
3358}
3359
3360
3361// Test that overwritten methods are not invoked on uncaught exception
3362// formatting. However, they are invoked when performing normal error
3363// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003364TEST(APIThrowMessageOverwrittenToString) {
3365 v8::HandleScope scope;
3366 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003367 Local<ObjectTemplate> templ = ObjectTemplate::New();
3368 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3369 LocalContext context(NULL, templ);
3370 CompileRun("asdf;");
3371 CompileRun("var limit = {};"
3372 "limit.valueOf = fail;"
3373 "Error.stackTraceLimit = limit;");
3374 CompileRun("asdf");
3375 CompileRun("Array.prototype.pop = fail;");
3376 CompileRun("Object.prototype.hasOwnProperty = fail;");
3377 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003378 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3379 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003380 CompileRun("ReferenceError.prototype.toString ="
3381 " function() { return 'Whoops' }");
3382 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003383 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3384 CompileRun("asdf;");
3385 CompileRun("ReferenceError.prototype.constructor = void 0;");
3386 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003387 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3388 CompileRun("asdf;");
3389 CompileRun("ReferenceError.prototype = new Object();");
3390 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003391 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3392 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003393 CompileRun("ReferenceError.prototype.constructor = new Object();"
3394 "ReferenceError.prototype.constructor.name = 1;"
3395 "Number.prototype.toString = function() { return 'Whoops'; };"
3396 "ReferenceError.prototype.toString = Object.prototype.toString;");
3397 CompileRun("asdf;");
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003398 v8::V8::RemoveMessageListeners(check_reference_error_message);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003399}
3400
3401
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003402static void check_custom_error_message(
3403 v8::Handle<v8::Message> message,
3404 v8::Handle<v8::Value> data) {
3405 const char* uncaught_error = "Uncaught MyError toString";
3406 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3407}
3408
3409
3410TEST(CustomErrorToString) {
3411 v8::HandleScope scope;
3412 v8::V8::AddMessageListener(check_custom_error_message);
3413 LocalContext context;
3414 CompileRun(
3415 "function MyError(name, message) { "
3416 " this.name = name; "
3417 " this.message = message; "
3418 "} "
3419 "MyError.prototype = Object.create(Error.prototype); "
3420 "MyError.prototype.toString = function() { "
3421 " return 'MyError toString'; "
3422 "}; "
3423 "throw new MyError('my name', 'my message'); ");
3424 v8::V8::RemoveMessageListeners(check_custom_error_message);
3425}
3426
3427
ager@chromium.org8bb60582008-12-11 12:02:20 +00003428static void receive_message(v8::Handle<v8::Message> message,
3429 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003430 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003431 message_received = true;
3432}
3433
3434
3435TEST(APIThrowMessage) {
3436 message_received = false;
3437 v8::HandleScope scope;
3438 v8::V8::AddMessageListener(receive_message);
3439 Local<ObjectTemplate> templ = ObjectTemplate::New();
3440 templ->Set(v8_str("ThrowFromC"),
3441 v8::FunctionTemplate::New(ThrowFromC));
3442 LocalContext context(0, templ);
3443 CompileRun("ThrowFromC();");
3444 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003445 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003446}
3447
3448
3449TEST(APIThrowMessageAndVerboseTryCatch) {
3450 message_received = false;
3451 v8::HandleScope scope;
3452 v8::V8::AddMessageListener(receive_message);
3453 Local<ObjectTemplate> templ = ObjectTemplate::New();
3454 templ->Set(v8_str("ThrowFromC"),
3455 v8::FunctionTemplate::New(ThrowFromC));
3456 LocalContext context(0, templ);
3457 v8::TryCatch try_catch;
3458 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003459 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003460 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003461 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003462 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003463 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003464}
3465
3466
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003467TEST(APIStackOverflowAndVerboseTryCatch) {
3468 message_received = false;
3469 v8::HandleScope scope;
3470 v8::V8::AddMessageListener(receive_message);
3471 LocalContext context;
3472 v8::TryCatch try_catch;
3473 try_catch.SetVerbose(true);
3474 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3475 CHECK(try_catch.HasCaught());
3476 CHECK(result.IsEmpty());
3477 CHECK(message_received);
3478 v8::V8::RemoveMessageListeners(receive_message);
3479}
3480
3481
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003482THREADED_TEST(ExternalScriptException) {
3483 v8::HandleScope scope;
3484 Local<ObjectTemplate> templ = ObjectTemplate::New();
3485 templ->Set(v8_str("ThrowFromC"),
3486 v8::FunctionTemplate::New(ThrowFromC));
3487 LocalContext context(0, templ);
3488
3489 v8::TryCatch try_catch;
3490 Local<Script> script
3491 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3492 Local<Value> result = script->Run();
3493 CHECK(result.IsEmpty());
3494 CHECK(try_catch.HasCaught());
3495 String::AsciiValue exception_value(try_catch.Exception());
3496 CHECK_EQ("konto", *exception_value);
3497}
3498
3499
3500
3501v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3502 ApiTestFuzzer::Fuzz();
3503 CHECK_EQ(4, args.Length());
3504 int count = args[0]->Int32Value();
3505 int cInterval = args[2]->Int32Value();
3506 if (count == 0) {
3507 return v8::ThrowException(v8_str("FromC"));
3508 } else {
3509 Local<v8::Object> global = Context::GetCurrent()->Global();
3510 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3511 v8::Handle<Value> argv[] = { v8_num(count - 1),
3512 args[1],
3513 args[2],
3514 args[3] };
3515 if (count % cInterval == 0) {
3516 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003517 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003518 int expected = args[3]->Int32Value();
3519 if (try_catch.HasCaught()) {
3520 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003521 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003522 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003523 } else {
3524 CHECK_NE(expected, count);
3525 }
3526 return result;
3527 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003528 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003529 }
3530 }
3531}
3532
3533
3534v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3535 ApiTestFuzzer::Fuzz();
3536 CHECK_EQ(3, args.Length());
3537 bool equality = args[0]->BooleanValue();
3538 int count = args[1]->Int32Value();
3539 int expected = args[2]->Int32Value();
3540 if (equality) {
3541 CHECK_EQ(count, expected);
3542 } else {
3543 CHECK_NE(count, expected);
3544 }
3545 return v8::Undefined();
3546}
3547
3548
ager@chromium.org8bb60582008-12-11 12:02:20 +00003549THREADED_TEST(EvalInTryFinally) {
3550 v8::HandleScope scope;
3551 LocalContext context;
3552 v8::TryCatch try_catch;
3553 CompileRun("(function() {"
3554 " try {"
3555 " eval('asldkf (*&^&*^');"
3556 " } finally {"
3557 " return;"
3558 " }"
3559 "})()");
3560 CHECK(!try_catch.HasCaught());
3561}
3562
3563
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003564// This test works by making a stack of alternating JavaScript and C
3565// activations. These activations set up exception handlers with regular
3566// intervals, one interval for C activations and another for JavaScript
3567// activations. When enough activations have been created an exception is
3568// thrown and we check that the right activation catches the exception and that
3569// no other activations do. The right activation is always the topmost one with
3570// a handler, regardless of whether it is in JavaScript or C.
3571//
3572// The notation used to describe a test case looks like this:
3573//
3574// *JS[4] *C[3] @JS[2] C[1] JS[0]
3575//
3576// Each entry is an activation, either JS or C. The index is the count at that
3577// level. Stars identify activations with exception handlers, the @ identifies
3578// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003579//
3580// BUG(271): Some of the exception propagation does not work on the
3581// ARM simulator because the simulator separates the C++ stack and the
3582// JS stack. This test therefore fails on the simulator. The test is
3583// not threaded to allow the threading tests to run on the simulator.
3584TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003585 v8::HandleScope scope;
3586 Local<ObjectTemplate> templ = ObjectTemplate::New();
3587 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3588 templ->Set(v8_str("CThrowCountDown"),
3589 v8::FunctionTemplate::New(CThrowCountDown));
3590 LocalContext context(0, templ);
3591 CompileRun(
3592 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3593 " if (count == 0) throw 'FromJS';"
3594 " if (count % jsInterval == 0) {"
3595 " try {"
3596 " var value = CThrowCountDown(count - 1,"
3597 " jsInterval,"
3598 " cInterval,"
3599 " expected);"
3600 " check(false, count, expected);"
3601 " return value;"
3602 " } catch (e) {"
3603 " check(true, count, expected);"
3604 " }"
3605 " } else {"
3606 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3607 " }"
3608 "}");
3609 Local<Function> fun =
3610 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3611
3612 const int argc = 4;
3613 // count jsInterval cInterval expected
3614
3615 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3616 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3617 fun->Call(fun, argc, a0);
3618
3619 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3620 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3621 fun->Call(fun, argc, a1);
3622
3623 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3624 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3625 fun->Call(fun, argc, a2);
3626
3627 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3628 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3629 fun->Call(fun, argc, a3);
3630
3631 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3632 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3633 fun->Call(fun, argc, a4);
3634
3635 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3636 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3637 fun->Call(fun, argc, a5);
3638}
3639
3640
3641v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3642 ApiTestFuzzer::Fuzz();
3643 CHECK_EQ(1, args.Length());
3644 return v8::ThrowException(args[0]);
3645}
3646
3647
3648THREADED_TEST(ThrowValues) {
3649 v8::HandleScope scope;
3650 Local<ObjectTemplate> templ = ObjectTemplate::New();
3651 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3652 LocalContext context(0, templ);
3653 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3654 "function Run(obj) {"
3655 " try {"
3656 " Throw(obj);"
3657 " } catch (e) {"
3658 " return e;"
3659 " }"
3660 " return 'no exception';"
3661 "}"
3662 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3663 CHECK_EQ(5, result->Length());
3664 CHECK(result->Get(v8::Integer::New(0))->IsString());
3665 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3666 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3667 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3668 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3669 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3670 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3671}
3672
3673
3674THREADED_TEST(CatchZero) {
3675 v8::HandleScope scope;
3676 LocalContext context;
3677 v8::TryCatch try_catch;
3678 CHECK(!try_catch.HasCaught());
3679 Script::Compile(v8_str("throw 10"))->Run();
3680 CHECK(try_catch.HasCaught());
3681 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3682 try_catch.Reset();
3683 CHECK(!try_catch.HasCaught());
3684 Script::Compile(v8_str("throw 0"))->Run();
3685 CHECK(try_catch.HasCaught());
3686 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3687}
3688
3689
3690THREADED_TEST(CatchExceptionFromWith) {
3691 v8::HandleScope scope;
3692 LocalContext context;
3693 v8::TryCatch try_catch;
3694 CHECK(!try_catch.HasCaught());
3695 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3696 CHECK(try_catch.HasCaught());
3697}
3698
3699
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003700THREADED_TEST(TryCatchAndFinallyHidingException) {
3701 v8::HandleScope scope;
3702 LocalContext context;
3703 v8::TryCatch try_catch;
3704 CHECK(!try_catch.HasCaught());
3705 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3706 CompileRun("f({toString: function() { throw 42; }});");
3707 CHECK(!try_catch.HasCaught());
3708}
3709
3710
3711v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3712 v8::TryCatch try_catch;
3713 return v8::Undefined();
3714}
3715
3716
3717THREADED_TEST(TryCatchAndFinally) {
3718 v8::HandleScope scope;
3719 LocalContext context;
3720 context->Global()->Set(
3721 v8_str("native_with_try_catch"),
3722 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3723 v8::TryCatch try_catch;
3724 CHECK(!try_catch.HasCaught());
3725 CompileRun(
3726 "try {\n"
3727 " throw new Error('a');\n"
3728 "} finally {\n"
3729 " native_with_try_catch();\n"
3730 "}\n");
3731 CHECK(try_catch.HasCaught());
3732}
3733
3734
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003735static void TryCatchNestedHelper(int depth) {
3736 if (depth > 0) {
3737 v8::TryCatch try_catch;
3738 try_catch.SetVerbose(true);
3739 TryCatchNestedHelper(depth - 1);
3740 CHECK(try_catch.HasCaught());
3741 try_catch.ReThrow();
3742 } else {
3743 v8::ThrowException(v8_str("back"));
3744 }
3745}
3746
3747
3748TEST(TryCatchNested) {
3749 v8::V8::Initialize();
3750 v8::HandleScope scope;
3751 LocalContext context;
3752 v8::TryCatch try_catch;
3753 TryCatchNestedHelper(5);
3754 CHECK(try_catch.HasCaught());
3755 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
3756}
3757
3758
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003759THREADED_TEST(Equality) {
3760 v8::HandleScope scope;
3761 LocalContext context;
3762 // Check that equality works at all before relying on CHECK_EQ
3763 CHECK(v8_str("a")->Equals(v8_str("a")));
3764 CHECK(!v8_str("a")->Equals(v8_str("b")));
3765
3766 CHECK_EQ(v8_str("a"), v8_str("a"));
3767 CHECK_NE(v8_str("a"), v8_str("b"));
3768 CHECK_EQ(v8_num(1), v8_num(1));
3769 CHECK_EQ(v8_num(1.00), v8_num(1));
3770 CHECK_NE(v8_num(1), v8_num(2));
3771
3772 // Assume String is not symbol.
3773 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3774 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3775 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3776 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3777 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3778 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3779 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3780 CHECK(!not_a_number->StrictEquals(not_a_number));
3781 CHECK(v8::False()->StrictEquals(v8::False()));
3782 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3783
3784 v8::Handle<v8::Object> obj = v8::Object::New();
3785 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3786 CHECK(alias->StrictEquals(obj));
3787 alias.Dispose();
3788}
3789
3790
3791THREADED_TEST(MultiRun) {
3792 v8::HandleScope scope;
3793 LocalContext context;
3794 Local<Script> script = Script::Compile(v8_str("x"));
3795 for (int i = 0; i < 10; i++)
3796 script->Run();
3797}
3798
3799
3800static v8::Handle<Value> GetXValue(Local<String> name,
3801 const AccessorInfo& info) {
3802 ApiTestFuzzer::Fuzz();
3803 CHECK_EQ(info.Data(), v8_str("donut"));
3804 CHECK_EQ(name, v8_str("x"));
3805 return name;
3806}
3807
3808
3809THREADED_TEST(SimplePropertyRead) {
3810 v8::HandleScope scope;
3811 Local<ObjectTemplate> templ = ObjectTemplate::New();
3812 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3813 LocalContext context;
3814 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3815 Local<Script> script = Script::Compile(v8_str("obj.x"));
3816 for (int i = 0; i < 10; i++) {
3817 Local<Value> result = script->Run();
3818 CHECK_EQ(result, v8_str("x"));
3819 }
3820}
3821
ager@chromium.org5c838252010-02-19 08:53:10 +00003822THREADED_TEST(DefinePropertyOnAPIAccessor) {
3823 v8::HandleScope scope;
3824 Local<ObjectTemplate> templ = ObjectTemplate::New();
3825 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3826 LocalContext context;
3827 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3828
3829 // Uses getOwnPropertyDescriptor to check the configurable status
3830 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003831 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 "obj, 'x');"
3833 "prop.configurable;"));
3834 Local<Value> result = script_desc->Run();
3835 CHECK_EQ(result->BooleanValue(), true);
3836
3837 // Redefine get - but still configurable
3838 Local<Script> script_define
3839 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3840 " configurable: true };"
3841 "Object.defineProperty(obj, 'x', desc);"
3842 "obj.x"));
3843 result = script_define->Run();
3844 CHECK_EQ(result, v8_num(42));
3845
3846 // Check that the accessor is still configurable
3847 result = script_desc->Run();
3848 CHECK_EQ(result->BooleanValue(), true);
3849
3850 // Redefine to a non-configurable
3851 script_define
3852 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3853 " configurable: false };"
3854 "Object.defineProperty(obj, 'x', desc);"
3855 "obj.x"));
3856 result = script_define->Run();
3857 CHECK_EQ(result, v8_num(43));
3858 result = script_desc->Run();
3859 CHECK_EQ(result->BooleanValue(), false);
3860
3861 // Make sure that it is not possible to redefine again
3862 v8::TryCatch try_catch;
3863 result = script_define->Run();
3864 CHECK(try_catch.HasCaught());
3865 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003866 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003867}
3868
3869THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3870 v8::HandleScope scope;
3871 Local<ObjectTemplate> templ = ObjectTemplate::New();
3872 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3873 LocalContext context;
3874 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3875
3876 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3877 "Object.getOwnPropertyDescriptor( "
3878 "obj, 'x');"
3879 "prop.configurable;"));
3880 Local<Value> result = script_desc->Run();
3881 CHECK_EQ(result->BooleanValue(), true);
3882
3883 Local<Script> script_define =
3884 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3885 " configurable: true };"
3886 "Object.defineProperty(obj, 'x', desc);"
3887 "obj.x"));
3888 result = script_define->Run();
3889 CHECK_EQ(result, v8_num(42));
3890
3891
3892 result = script_desc->Run();
3893 CHECK_EQ(result->BooleanValue(), true);
3894
3895
3896 script_define =
3897 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3898 " configurable: false };"
3899 "Object.defineProperty(obj, 'x', desc);"
3900 "obj.x"));
3901 result = script_define->Run();
3902 CHECK_EQ(result, v8_num(43));
3903 result = script_desc->Run();
3904
3905 CHECK_EQ(result->BooleanValue(), false);
3906
3907 v8::TryCatch try_catch;
3908 result = script_define->Run();
3909 CHECK(try_catch.HasCaught());
3910 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003911 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003912}
3913
3914
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003915static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3916 char const* name) {
3917 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3918}
ager@chromium.org5c838252010-02-19 08:53:10 +00003919
3920
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003921THREADED_TEST(DefineAPIAccessorOnObject) {
3922 v8::HandleScope scope;
3923 Local<ObjectTemplate> templ = ObjectTemplate::New();
3924 LocalContext context;
3925
3926 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3927 CompileRun("var obj2 = {};");
3928
3929 CHECK(CompileRun("obj1.x")->IsUndefined());
3930 CHECK(CompileRun("obj2.x")->IsUndefined());
3931
3932 CHECK(GetGlobalProperty(&context, "obj1")->
3933 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3934
3935 ExpectString("obj1.x", "x");
3936 CHECK(CompileRun("obj2.x")->IsUndefined());
3937
3938 CHECK(GetGlobalProperty(&context, "obj2")->
3939 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3940
3941 ExpectString("obj1.x", "x");
3942 ExpectString("obj2.x", "x");
3943
3944 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3945 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3946
3947 CompileRun("Object.defineProperty(obj1, 'x',"
3948 "{ get: function() { return 'y'; }, configurable: true })");
3949
3950 ExpectString("obj1.x", "y");
3951 ExpectString("obj2.x", "x");
3952
3953 CompileRun("Object.defineProperty(obj2, 'x',"
3954 "{ get: function() { return 'y'; }, configurable: true })");
3955
3956 ExpectString("obj1.x", "y");
3957 ExpectString("obj2.x", "y");
3958
3959 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3960 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3961
3962 CHECK(GetGlobalProperty(&context, "obj1")->
3963 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3964 CHECK(GetGlobalProperty(&context, "obj2")->
3965 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3966
3967 ExpectString("obj1.x", "x");
3968 ExpectString("obj2.x", "x");
3969
3970 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3971 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3972
3973 // Define getters/setters, but now make them not configurable.
3974 CompileRun("Object.defineProperty(obj1, 'x',"
3975 "{ get: function() { return 'z'; }, configurable: false })");
3976 CompileRun("Object.defineProperty(obj2, 'x',"
3977 "{ get: function() { return 'z'; }, configurable: false })");
3978
3979 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3980 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3981
3982 ExpectString("obj1.x", "z");
3983 ExpectString("obj2.x", "z");
3984
3985 CHECK(!GetGlobalProperty(&context, "obj1")->
3986 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3987 CHECK(!GetGlobalProperty(&context, "obj2")->
3988 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3989
3990 ExpectString("obj1.x", "z");
3991 ExpectString("obj2.x", "z");
3992}
3993
3994
3995THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3996 v8::HandleScope scope;
3997 Local<ObjectTemplate> templ = ObjectTemplate::New();
3998 LocalContext context;
3999
4000 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4001 CompileRun("var obj2 = {};");
4002
4003 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4004 v8_str("x"),
4005 GetXValue, NULL,
4006 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4007 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4008 v8_str("x"),
4009 GetXValue, NULL,
4010 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4011
4012 ExpectString("obj1.x", "x");
4013 ExpectString("obj2.x", "x");
4014
4015 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4016 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4017
4018 CHECK(!GetGlobalProperty(&context, "obj1")->
4019 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4020 CHECK(!GetGlobalProperty(&context, "obj2")->
4021 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4022
4023 {
4024 v8::TryCatch try_catch;
4025 CompileRun("Object.defineProperty(obj1, 'x',"
4026 "{get: function() { return 'func'; }})");
4027 CHECK(try_catch.HasCaught());
4028 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004029 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004030 }
4031 {
4032 v8::TryCatch try_catch;
4033 CompileRun("Object.defineProperty(obj2, 'x',"
4034 "{get: function() { return 'func'; }})");
4035 CHECK(try_catch.HasCaught());
4036 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004037 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004038 }
4039}
4040
4041
4042static v8::Handle<Value> Get239Value(Local<String> name,
4043 const AccessorInfo& info) {
4044 ApiTestFuzzer::Fuzz();
4045 CHECK_EQ(info.Data(), v8_str("donut"));
4046 CHECK_EQ(name, v8_str("239"));
4047 return name;
4048}
4049
4050
4051THREADED_TEST(ElementAPIAccessor) {
4052 v8::HandleScope scope;
4053 Local<ObjectTemplate> templ = ObjectTemplate::New();
4054 LocalContext context;
4055
4056 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4057 CompileRun("var obj2 = {};");
4058
4059 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4060 v8_str("239"),
4061 Get239Value, NULL,
4062 v8_str("donut")));
4063 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4064 v8_str("239"),
4065 Get239Value, NULL,
4066 v8_str("donut")));
4067
4068 ExpectString("obj1[239]", "239");
4069 ExpectString("obj2[239]", "239");
4070 ExpectString("obj1['239']", "239");
4071 ExpectString("obj2['239']", "239");
4072}
4073
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004074
4075v8::Persistent<Value> xValue;
4076
4077
4078static void SetXValue(Local<String> name,
4079 Local<Value> value,
4080 const AccessorInfo& info) {
4081 CHECK_EQ(value, v8_num(4));
4082 CHECK_EQ(info.Data(), v8_str("donut"));
4083 CHECK_EQ(name, v8_str("x"));
4084 CHECK(xValue.IsEmpty());
4085 xValue = v8::Persistent<Value>::New(value);
4086}
4087
4088
4089THREADED_TEST(SimplePropertyWrite) {
4090 v8::HandleScope scope;
4091 Local<ObjectTemplate> templ = ObjectTemplate::New();
4092 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
4093 LocalContext context;
4094 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4095 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
4096 for (int i = 0; i < 10; i++) {
4097 CHECK(xValue.IsEmpty());
4098 script->Run();
4099 CHECK_EQ(v8_num(4), xValue);
4100 xValue.Dispose();
4101 xValue = v8::Persistent<Value>();
4102 }
4103}
4104
4105
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004106THREADED_TEST(SetterOnly) {
4107 v8::HandleScope scope;
4108 Local<ObjectTemplate> templ = ObjectTemplate::New();
4109 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
4110 LocalContext context;
4111 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4112 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4113 for (int i = 0; i < 10; i++) {
4114 CHECK(xValue.IsEmpty());
4115 script->Run();
4116 CHECK_EQ(v8_num(4), xValue);
4117 xValue.Dispose();
4118 xValue = v8::Persistent<Value>();
4119 }
4120}
4121
4122
4123THREADED_TEST(NoAccessors) {
4124 v8::HandleScope scope;
4125 Local<ObjectTemplate> templ = ObjectTemplate::New();
4126 templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
4127 LocalContext context;
4128 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4129 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4130 for (int i = 0; i < 10; i++) {
4131 script->Run();
4132 }
4133}
4134
4135
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004136static v8::Handle<Value> XPropertyGetter(Local<String> property,
4137 const AccessorInfo& info) {
4138 ApiTestFuzzer::Fuzz();
4139 CHECK(info.Data()->IsUndefined());
4140 return property;
4141}
4142
4143
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004144THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004145 v8::HandleScope scope;
4146 Local<ObjectTemplate> templ = ObjectTemplate::New();
4147 templ->SetNamedPropertyHandler(XPropertyGetter);
4148 LocalContext context;
4149 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4150 Local<Script> script = Script::Compile(v8_str("obj.x"));
4151 for (int i = 0; i < 10; i++) {
4152 Local<Value> result = script->Run();
4153 CHECK_EQ(result, v8_str("x"));
4154 }
4155}
4156
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004157
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004158THREADED_TEST(NamedInterceptorDictionaryIC) {
4159 v8::HandleScope scope;
4160 Local<ObjectTemplate> templ = ObjectTemplate::New();
4161 templ->SetNamedPropertyHandler(XPropertyGetter);
4162 LocalContext context;
4163 // Create an object with a named interceptor.
4164 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
4165 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
4166 for (int i = 0; i < 10; i++) {
4167 Local<Value> result = script->Run();
4168 CHECK_EQ(result, v8_str("x"));
4169 }
4170 // Create a slow case object and a function accessing a property in
4171 // that slow case object (with dictionary probing in generated
4172 // code). Then force object with a named interceptor into slow-case,
4173 // pass it to the function, and check that the interceptor is called
4174 // instead of accessing the local property.
4175 Local<Value> result =
4176 CompileRun("function get_x(o) { return o.x; };"
4177 "var obj = { x : 42, y : 0 };"
4178 "delete obj.y;"
4179 "for (var i = 0; i < 10; i++) get_x(obj);"
4180 "interceptor_obj.x = 42;"
4181 "interceptor_obj.y = 10;"
4182 "delete interceptor_obj.y;"
4183 "get_x(interceptor_obj)");
4184 CHECK_EQ(result, v8_str("x"));
4185}
4186
4187
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004188THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
4189 v8::HandleScope scope;
4190
4191 v8::Persistent<Context> context1 = Context::New();
4192
4193 context1->Enter();
4194 Local<ObjectTemplate> templ = ObjectTemplate::New();
4195 templ->SetNamedPropertyHandler(XPropertyGetter);
4196 // Create an object with a named interceptor.
4197 v8::Local<v8::Object> object = templ->NewInstance();
4198 context1->Global()->Set(v8_str("interceptor_obj"), object);
4199
4200 // Force the object into the slow case.
4201 CompileRun("interceptor_obj.y = 0;"
4202 "delete interceptor_obj.y;");
4203 context1->Exit();
4204
4205 {
4206 // Introduce the object into a different context.
4207 // Repeat named loads to exercise ICs.
4208 LocalContext context2;
4209 context2->Global()->Set(v8_str("interceptor_obj"), object);
4210 Local<Value> result =
4211 CompileRun("function get_x(o) { return o.x; }"
4212 "interceptor_obj.x = 42;"
4213 "for (var i=0; i != 10; i++) {"
4214 " get_x(interceptor_obj);"
4215 "}"
4216 "get_x(interceptor_obj)");
4217 // Check that the interceptor was actually invoked.
4218 CHECK_EQ(result, v8_str("x"));
4219 }
4220
4221 // Return to the original context and force some object to the slow case
4222 // to cause the NormalizedMapCache to verify.
4223 context1->Enter();
4224 CompileRun("var obj = { x : 0 }; delete obj.x;");
4225 context1->Exit();
4226
4227 context1.Dispose();
4228}
4229
4230
ager@chromium.org5c838252010-02-19 08:53:10 +00004231static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
4232 const AccessorInfo& info) {
4233 // Set x on the prototype object and do not handle the get request.
4234 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004235 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00004236 return v8::Handle<Value>();
4237}
4238
4239
4240// This is a regression test for http://crbug.com/20104. Map
4241// transitions should not interfere with post interceptor lookup.
4242THREADED_TEST(NamedInterceptorMapTransitionRead) {
4243 v8::HandleScope scope;
4244 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
4245 Local<v8::ObjectTemplate> instance_template
4246 = function_template->InstanceTemplate();
4247 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
4248 LocalContext context;
4249 context->Global()->Set(v8_str("F"), function_template->GetFunction());
4250 // Create an instance of F and introduce a map transition for x.
4251 CompileRun("var o = new F(); o.x = 23;");
4252 // Create an instance of F and invoke the getter. The result should be 23.
4253 Local<Value> result = CompileRun("o = new F(); o.x");
4254 CHECK_EQ(result->Int32Value(), 23);
4255}
4256
4257
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004258static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4259 const AccessorInfo& info) {
4260 ApiTestFuzzer::Fuzz();
4261 if (index == 37) {
4262 return v8::Handle<Value>(v8_num(625));
4263 }
4264 return v8::Handle<Value>();
4265}
4266
4267
4268static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4269 Local<Value> value,
4270 const AccessorInfo& info) {
4271 ApiTestFuzzer::Fuzz();
4272 if (index == 39) {
4273 return value;
4274 }
4275 return v8::Handle<Value>();
4276}
4277
4278
4279THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
4280 v8::HandleScope scope;
4281 Local<ObjectTemplate> templ = ObjectTemplate::New();
4282 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4283 IndexedPropertySetter);
4284 LocalContext context;
4285 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4286 Local<Script> getter_script = Script::Compile(v8_str(
4287 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4288 Local<Script> setter_script = Script::Compile(v8_str(
4289 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4290 "obj[17] = 23;"
4291 "obj.foo;"));
4292 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4293 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4294 "obj[39] = 47;"
4295 "obj.foo;")); // This setter should not run, due to the interceptor.
4296 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4297 "obj[37];"));
4298 Local<Value> result = getter_script->Run();
4299 CHECK_EQ(v8_num(5), result);
4300 result = setter_script->Run();
4301 CHECK_EQ(v8_num(23), result);
4302 result = interceptor_setter_script->Run();
4303 CHECK_EQ(v8_num(23), result);
4304 result = interceptor_getter_script->Run();
4305 CHECK_EQ(v8_num(625), result);
4306}
4307
4308
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004309static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4310 uint32_t index,
4311 const AccessorInfo& info) {
4312 ApiTestFuzzer::Fuzz();
4313 if (index < 25) {
4314 return v8::Handle<Value>(v8_num(index));
4315 }
4316 return v8::Handle<Value>();
4317}
4318
4319
4320static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4321 uint32_t index,
4322 Local<Value> value,
4323 const AccessorInfo& info) {
4324 ApiTestFuzzer::Fuzz();
4325 if (index < 25) {
4326 return v8::Handle<Value>(v8_num(index));
4327 }
4328 return v8::Handle<Value>();
4329}
4330
4331
4332Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
4333 const AccessorInfo& info) {
4334 // Force the list of returned keys to be stored in a FastDoubleArray.
4335 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4336 "keys = new Array(); keys[125000] = 1;"
4337 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4338 "keys.length = 25; keys;"));
4339 Local<Value> result = indexed_property_names_script->Run();
4340 return Local<v8::Array>(::v8::Array::Cast(*result));
4341}
4342
4343
4344// Make sure that the the interceptor code in the runtime properly handles
4345// merging property name lists for double-array-backed arrays.
4346THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
4347 v8::HandleScope scope;
4348 Local<ObjectTemplate> templ = ObjectTemplate::New();
4349 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4350 UnboxedDoubleIndexedPropertySetter,
4351 0,
4352 0,
4353 UnboxedDoubleIndexedPropertyEnumerator);
4354 LocalContext context;
4355 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4356 // When obj is created, force it to be Stored in a FastDoubleArray.
4357 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4358 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4359 "key_count = 0; "
4360 "for (x in obj) {key_count++;};"
4361 "obj;"));
4362 Local<Value> result = create_unboxed_double_script->Run();
4363 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4364 Local<Script> key_count_check = Script::Compile(v8_str(
4365 "key_count;"));
4366 result = key_count_check->Run();
4367 CHECK_EQ(v8_num(40013), result);
4368}
4369
4370
rossberg@chromium.org28a37082011-08-22 11:03:23 +00004371Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
4372 const AccessorInfo& info) {
4373 // Force the list of returned keys to be stored in a Arguments object.
4374 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4375 "function f(w,x) {"
4376 " return arguments;"
4377 "}"
4378 "keys = f(0, 1, 2, 3);"
4379 "keys;"));
4380 Local<Value> result = indexed_property_names_script->Run();
4381 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4382}
4383
4384
4385static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4386 uint32_t index,
4387 const AccessorInfo& info) {
4388 ApiTestFuzzer::Fuzz();
4389 if (index < 4) {
4390 return v8::Handle<Value>(v8_num(index));
4391 }
4392 return v8::Handle<Value>();
4393}
4394
4395
4396// Make sure that the the interceptor code in the runtime properly handles
4397// merging property name lists for non-string arguments arrays.
4398THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
4399 v8::HandleScope scope;
4400 Local<ObjectTemplate> templ = ObjectTemplate::New();
4401 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4402 0,
4403 0,
4404 0,
4405 NonStrictArgsIndexedPropertyEnumerator);
4406 LocalContext context;
4407 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4408 Local<Script> create_args_script =
4409 Script::Compile(v8_str(
4410 "var key_count = 0;"
4411 "for (x in obj) {key_count++;} key_count;"));
4412 Local<Value> result = create_args_script->Run();
4413 CHECK_EQ(v8_num(4), result);
4414}
4415
4416
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004417static v8::Handle<Value> IdentityIndexedPropertyGetter(
4418 uint32_t index,
4419 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004420 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004421}
4422
4423
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004424THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4425 v8::HandleScope scope;
4426 Local<ObjectTemplate> templ = ObjectTemplate::New();
4427 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4428
4429 LocalContext context;
4430 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4431
4432 // Check fast object case.
4433 const char* fast_case_code =
4434 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4435 ExpectString(fast_case_code, "0");
4436
4437 // Check slow case.
4438 const char* slow_case_code =
4439 "obj.x = 1; delete obj.x;"
4440 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4441 ExpectString(slow_case_code, "1");
4442}
4443
4444
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004445THREADED_TEST(IndexedInterceptorWithNoSetter) {
4446 v8::HandleScope scope;
4447 Local<ObjectTemplate> templ = ObjectTemplate::New();
4448 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4449
4450 LocalContext context;
4451 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4452
4453 const char* code =
4454 "try {"
4455 " obj[0] = 239;"
4456 " for (var i = 0; i < 100; i++) {"
4457 " var v = obj[0];"
4458 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4459 " }"
4460 " 'PASSED'"
4461 "} catch(e) {"
4462 " e"
4463 "}";
4464 ExpectString(code, "PASSED");
4465}
4466
4467
ager@chromium.org5c838252010-02-19 08:53:10 +00004468THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4469 v8::HandleScope scope;
4470 Local<ObjectTemplate> templ = ObjectTemplate::New();
4471 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4472
4473 LocalContext context;
4474 Local<v8::Object> obj = templ->NewInstance();
4475 obj->TurnOnAccessCheck();
4476 context->Global()->Set(v8_str("obj"), obj);
4477
4478 const char* code =
4479 "try {"
4480 " for (var i = 0; i < 100; i++) {"
4481 " var v = obj[0];"
4482 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4483 " }"
4484 " 'PASSED'"
4485 "} catch(e) {"
4486 " e"
4487 "}";
4488 ExpectString(code, "PASSED");
4489}
4490
4491
4492THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4493 i::FLAG_allow_natives_syntax = true;
4494 v8::HandleScope scope;
4495 Local<ObjectTemplate> templ = ObjectTemplate::New();
4496 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4497
4498 LocalContext context;
4499 Local<v8::Object> obj = templ->NewInstance();
4500 context->Global()->Set(v8_str("obj"), obj);
4501
4502 const char* code =
4503 "try {"
4504 " for (var i = 0; i < 100; i++) {"
4505 " var expected = i;"
4506 " if (i == 5) {"
4507 " %EnableAccessChecks(obj);"
4508 " expected = undefined;"
4509 " }"
4510 " var v = obj[i];"
4511 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4512 " if (i == 5) %DisableAccessChecks(obj);"
4513 " }"
4514 " 'PASSED'"
4515 "} catch(e) {"
4516 " e"
4517 "}";
4518 ExpectString(code, "PASSED");
4519}
4520
4521
4522THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4523 v8::HandleScope scope;
4524 Local<ObjectTemplate> templ = ObjectTemplate::New();
4525 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4526
4527 LocalContext context;
4528 Local<v8::Object> obj = templ->NewInstance();
4529 context->Global()->Set(v8_str("obj"), obj);
4530
4531 const char* code =
4532 "try {"
4533 " for (var i = 0; i < 100; i++) {"
4534 " var v = obj[i];"
4535 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4536 " }"
4537 " 'PASSED'"
4538 "} catch(e) {"
4539 " e"
4540 "}";
4541 ExpectString(code, "PASSED");
4542}
4543
4544
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004545THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4546 v8::HandleScope scope;
4547 Local<ObjectTemplate> templ = ObjectTemplate::New();
4548 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4549
4550 LocalContext context;
4551 Local<v8::Object> obj = templ->NewInstance();
4552 context->Global()->Set(v8_str("obj"), obj);
4553
4554 const char* code =
4555 "try {"
4556 " for (var i = 0; i < 100; i++) {"
4557 " var expected = i;"
4558 " var key = i;"
4559 " if (i == 25) {"
4560 " key = -1;"
4561 " expected = undefined;"
4562 " }"
4563 " if (i == 50) {"
4564 " /* probe minimal Smi number on 32-bit platforms */"
4565 " key = -(1 << 30);"
4566 " expected = undefined;"
4567 " }"
4568 " if (i == 75) {"
4569 " /* probe minimal Smi number on 64-bit platforms */"
4570 " key = 1 << 31;"
4571 " expected = undefined;"
4572 " }"
4573 " var v = obj[key];"
4574 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4575 " }"
4576 " 'PASSED'"
4577 "} catch(e) {"
4578 " e"
4579 "}";
4580 ExpectString(code, "PASSED");
4581}
4582
4583
ager@chromium.org5c838252010-02-19 08:53:10 +00004584THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4585 v8::HandleScope scope;
4586 Local<ObjectTemplate> templ = ObjectTemplate::New();
4587 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4588
4589 LocalContext context;
4590 Local<v8::Object> obj = templ->NewInstance();
4591 context->Global()->Set(v8_str("obj"), obj);
4592
4593 const char* code =
4594 "try {"
4595 " for (var i = 0; i < 100; i++) {"
4596 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004597 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004598 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004599 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004600 " expected = undefined;"
4601 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004602 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004603 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4604 " }"
4605 " 'PASSED'"
4606 "} catch(e) {"
4607 " e"
4608 "}";
4609 ExpectString(code, "PASSED");
4610}
4611
4612
4613THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4614 v8::HandleScope scope;
4615 Local<ObjectTemplate> templ = ObjectTemplate::New();
4616 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4617
4618 LocalContext context;
4619 Local<v8::Object> obj = templ->NewInstance();
4620 context->Global()->Set(v8_str("obj"), obj);
4621
4622 const char* code =
4623 "var original = obj;"
4624 "try {"
4625 " for (var i = 0; i < 100; i++) {"
4626 " var expected = i;"
4627 " if (i == 50) {"
4628 " obj = {50: 'foobar'};"
4629 " expected = 'foobar';"
4630 " }"
4631 " var v = obj[i];"
4632 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4633 " if (i == 50) obj = original;"
4634 " }"
4635 " 'PASSED'"
4636 "} catch(e) {"
4637 " e"
4638 "}";
4639 ExpectString(code, "PASSED");
4640}
4641
4642
4643THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4644 v8::HandleScope scope;
4645 Local<ObjectTemplate> templ = ObjectTemplate::New();
4646 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4647
4648 LocalContext context;
4649 Local<v8::Object> obj = templ->NewInstance();
4650 context->Global()->Set(v8_str("obj"), obj);
4651
4652 const char* code =
4653 "var original = obj;"
4654 "try {"
4655 " for (var i = 0; i < 100; i++) {"
4656 " var expected = i;"
4657 " if (i == 5) {"
4658 " obj = 239;"
4659 " expected = undefined;"
4660 " }"
4661 " var v = obj[i];"
4662 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4663 " if (i == 5) obj = original;"
4664 " }"
4665 " 'PASSED'"
4666 "} catch(e) {"
4667 " e"
4668 "}";
4669 ExpectString(code, "PASSED");
4670}
4671
4672
4673THREADED_TEST(IndexedInterceptorOnProto) {
4674 v8::HandleScope scope;
4675 Local<ObjectTemplate> templ = ObjectTemplate::New();
4676 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4677
4678 LocalContext context;
4679 Local<v8::Object> obj = templ->NewInstance();
4680 context->Global()->Set(v8_str("obj"), obj);
4681
4682 const char* code =
4683 "var o = {__proto__: obj};"
4684 "try {"
4685 " for (var i = 0; i < 100; i++) {"
4686 " var v = o[i];"
4687 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4688 " }"
4689 " 'PASSED'"
4690 "} catch(e) {"
4691 " e"
4692 "}";
4693 ExpectString(code, "PASSED");
4694}
4695
4696
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004697THREADED_TEST(MultiContexts) {
4698 v8::HandleScope scope;
4699 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4700 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4701
4702 Local<String> password = v8_str("Password");
4703
4704 // Create an environment
4705 LocalContext context0(0, templ);
4706 context0->SetSecurityToken(password);
4707 v8::Handle<v8::Object> global0 = context0->Global();
4708 global0->Set(v8_str("custom"), v8_num(1234));
4709 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4710
4711 // Create an independent environment
4712 LocalContext context1(0, templ);
4713 context1->SetSecurityToken(password);
4714 v8::Handle<v8::Object> global1 = context1->Global();
4715 global1->Set(v8_str("custom"), v8_num(1234));
4716 CHECK_NE(global0, global1);
4717 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4718 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4719
4720 // Now create a new context with the old global
4721 LocalContext context2(0, templ, global1);
4722 context2->SetSecurityToken(password);
4723 v8::Handle<v8::Object> global2 = context2->Global();
4724 CHECK_EQ(global1, global2);
4725 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4726 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4727}
4728
4729
4730THREADED_TEST(FunctionPrototypeAcrossContexts) {
4731 // Make sure that functions created by cloning boilerplates cannot
4732 // communicate through their __proto__ field.
4733
4734 v8::HandleScope scope;
4735
4736 LocalContext env0;
4737 v8::Handle<v8::Object> global0 =
4738 env0->Global();
4739 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004740 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004741 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004742 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004743 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004744 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004745 proto0->Set(v8_str("custom"), v8_num(1234));
4746
4747 LocalContext env1;
4748 v8::Handle<v8::Object> global1 =
4749 env1->Global();
4750 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004751 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004752 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004753 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004754 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004755 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004756 CHECK(!proto1->Has(v8_str("custom")));
4757}
4758
4759
4760THREADED_TEST(Regress892105) {
4761 // Make sure that object and array literals created by cloning
4762 // boilerplates cannot communicate through their __proto__
4763 // field. This is rather difficult to check, but we try to add stuff
4764 // to Object.prototype and Array.prototype and create a new
4765 // environment. This should succeed.
4766
4767 v8::HandleScope scope;
4768
4769 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4770 "Array.prototype.arr = 4567;"
4771 "8901");
4772
4773 LocalContext env0;
4774 Local<Script> script0 = Script::Compile(source);
4775 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4776
4777 LocalContext env1;
4778 Local<Script> script1 = Script::Compile(source);
4779 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4780}
4781
4782
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004783THREADED_TEST(UndetectableObject) {
4784 v8::HandleScope scope;
4785 LocalContext env;
4786
4787 Local<v8::FunctionTemplate> desc =
4788 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4789 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4790
4791 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4792 env->Global()->Set(v8_str("undetectable"), obj);
4793
4794 ExpectString("undetectable.toString()", "[object Object]");
4795 ExpectString("typeof undetectable", "undefined");
4796 ExpectString("typeof(undetectable)", "undefined");
4797 ExpectBoolean("typeof undetectable == 'undefined'", true);
4798 ExpectBoolean("typeof undetectable == 'object'", false);
4799 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4800 ExpectBoolean("!undetectable", true);
4801
4802 ExpectObject("true&&undetectable", obj);
4803 ExpectBoolean("false&&undetectable", false);
4804 ExpectBoolean("true||undetectable", true);
4805 ExpectObject("false||undetectable", obj);
4806
4807 ExpectObject("undetectable&&true", obj);
4808 ExpectObject("undetectable&&false", obj);
4809 ExpectBoolean("undetectable||true", true);
4810 ExpectBoolean("undetectable||false", false);
4811
4812 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004813 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004814 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004815 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004816 ExpectBoolean("undetectable==undetectable", true);
4817
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004818
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004819 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004820 ExpectBoolean("null===undetectable", false);
4821 ExpectBoolean("undetectable===undefined", false);
4822 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004823 ExpectBoolean("undetectable===undetectable", true);
4824}
4825
4826
ager@chromium.org04921a82011-06-27 13:21:41 +00004827THREADED_TEST(VoidLiteral) {
4828 v8::HandleScope scope;
4829 LocalContext env;
4830
4831 Local<v8::FunctionTemplate> desc =
4832 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4833 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4834
4835 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4836 env->Global()->Set(v8_str("undetectable"), obj);
4837
4838 ExpectBoolean("undefined == void 0", true);
4839 ExpectBoolean("undetectable == void 0", true);
4840 ExpectBoolean("null == void 0", true);
4841 ExpectBoolean("undefined === void 0", true);
4842 ExpectBoolean("undetectable === void 0", false);
4843 ExpectBoolean("null === void 0", false);
4844
4845 ExpectBoolean("void 0 == undefined", true);
4846 ExpectBoolean("void 0 == undetectable", true);
4847 ExpectBoolean("void 0 == null", true);
4848 ExpectBoolean("void 0 === undefined", true);
4849 ExpectBoolean("void 0 === undetectable", false);
4850 ExpectBoolean("void 0 === null", false);
4851
4852 ExpectString("(function() {"
4853 " try {"
4854 " return x === void 0;"
4855 " } catch(e) {"
4856 " return e.toString();"
4857 " }"
4858 "})()",
4859 "ReferenceError: x is not defined");
4860 ExpectString("(function() {"
4861 " try {"
4862 " return void 0 === x;"
4863 " } catch(e) {"
4864 " return e.toString();"
4865 " }"
4866 "})()",
4867 "ReferenceError: x is not defined");
4868}
4869
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004870
4871THREADED_TEST(ExtensibleOnUndetectable) {
4872 v8::HandleScope scope;
4873 LocalContext env;
4874
4875 Local<v8::FunctionTemplate> desc =
4876 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4877 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4878
4879 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4880 env->Global()->Set(v8_str("undetectable"), obj);
4881
4882 Local<String> source = v8_str("undetectable.x = 42;"
4883 "undetectable.x");
4884
4885 Local<Script> script = Script::Compile(source);
4886
4887 CHECK_EQ(v8::Integer::New(42), script->Run());
4888
4889 ExpectBoolean("Object.isExtensible(undetectable)", true);
4890
4891 source = v8_str("Object.preventExtensions(undetectable);");
4892 script = Script::Compile(source);
4893 script->Run();
4894 ExpectBoolean("Object.isExtensible(undetectable)", false);
4895
4896 source = v8_str("undetectable.y = 2000;");
4897 script = Script::Compile(source);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004898 script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004899 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004900}
4901
4902
4903
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004904THREADED_TEST(UndetectableString) {
4905 v8::HandleScope scope;
4906 LocalContext env;
4907
4908 Local<String> obj = String::NewUndetectable("foo");
4909 env->Global()->Set(v8_str("undetectable"), obj);
4910
4911 ExpectString("undetectable", "foo");
4912 ExpectString("typeof undetectable", "undefined");
4913 ExpectString("typeof(undetectable)", "undefined");
4914 ExpectBoolean("typeof undetectable == 'undefined'", true);
4915 ExpectBoolean("typeof undetectable == 'string'", false);
4916 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4917 ExpectBoolean("!undetectable", true);
4918
4919 ExpectObject("true&&undetectable", obj);
4920 ExpectBoolean("false&&undetectable", false);
4921 ExpectBoolean("true||undetectable", true);
4922 ExpectObject("false||undetectable", obj);
4923
4924 ExpectObject("undetectable&&true", obj);
4925 ExpectObject("undetectable&&false", obj);
4926 ExpectBoolean("undetectable||true", true);
4927 ExpectBoolean("undetectable||false", false);
4928
4929 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004930 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004931 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004932 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004933 ExpectBoolean("undetectable==undetectable", true);
4934
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004935
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004936 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004937 ExpectBoolean("null===undetectable", false);
4938 ExpectBoolean("undetectable===undefined", false);
4939 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004940 ExpectBoolean("undetectable===undetectable", true);
4941}
4942
4943
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004944TEST(UndetectableOptimized) {
4945 i::FLAG_allow_natives_syntax = true;
4946 v8::HandleScope scope;
4947 LocalContext env;
4948
4949 Local<String> obj = String::NewUndetectable("foo");
4950 env->Global()->Set(v8_str("undetectable"), obj);
4951 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4952
4953 ExpectString(
4954 "function testBranch() {"
4955 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4956 " if (%_IsUndetectableObject(detectable)) throw 2;"
4957 "}\n"
4958 "function testBool() {"
4959 " var b1 = !%_IsUndetectableObject(undetectable);"
4960 " var b2 = %_IsUndetectableObject(detectable);"
4961 " if (b1) throw 3;"
4962 " if (b2) throw 4;"
4963 " return b1 == b2;"
4964 "}\n"
4965 "%OptimizeFunctionOnNextCall(testBranch);"
4966 "%OptimizeFunctionOnNextCall(testBool);"
4967 "for (var i = 0; i < 10; i++) {"
4968 " testBranch();"
4969 " testBool();"
4970 "}\n"
4971 "\"PASS\"",
4972 "PASS");
4973}
4974
4975
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004976template <typename T> static void USE(T) { }
4977
4978
4979// This test is not intended to be run, just type checked.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004980static inline void PersistentHandles() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004981 USE(PersistentHandles);
4982 Local<String> str = v8_str("foo");
4983 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4984 USE(p_str);
4985 Local<Script> scr = Script::Compile(v8_str(""));
4986 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4987 USE(p_scr);
4988 Local<ObjectTemplate> templ = ObjectTemplate::New();
4989 v8::Persistent<ObjectTemplate> p_templ =
4990 v8::Persistent<ObjectTemplate>::New(templ);
4991 USE(p_templ);
4992}
4993
4994
4995static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4996 ApiTestFuzzer::Fuzz();
4997 return v8::Undefined();
4998}
4999
5000
5001THREADED_TEST(GlobalObjectTemplate) {
5002 v8::HandleScope handle_scope;
5003 Local<ObjectTemplate> global_template = ObjectTemplate::New();
5004 global_template->Set(v8_str("JSNI_Log"),
5005 v8::FunctionTemplate::New(HandleLogDelegator));
5006 v8::Persistent<Context> context = Context::New(0, global_template);
5007 Context::Scope context_scope(context);
5008 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
5009 context.Dispose();
5010}
5011
5012
5013static const char* kSimpleExtensionSource =
5014 "function Foo() {"
5015 " return 4;"
5016 "}";
5017
5018
5019THREADED_TEST(SimpleExtensions) {
5020 v8::HandleScope handle_scope;
5021 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
5022 const char* extension_names[] = { "simpletest" };
5023 v8::ExtensionConfiguration extensions(1, extension_names);
5024 v8::Handle<Context> context = Context::New(&extensions);
5025 Context::Scope lock(context);
5026 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5027 CHECK_EQ(result, v8::Integer::New(4));
5028}
5029
5030
danno@chromium.org412fa512012-09-14 13:28:26 +00005031THREADED_TEST(NullExtensions) {
5032 v8::HandleScope handle_scope;
5033 v8::RegisterExtension(new Extension("nulltest", NULL));
5034 const char* extension_names[] = { "nulltest" };
5035 v8::ExtensionConfiguration extensions(1, extension_names);
5036 v8::Handle<Context> context = Context::New(&extensions);
5037 Context::Scope lock(context);
5038 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
5039 CHECK_EQ(result, v8::Integer::New(4));
5040}
5041
5042
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005043static const char* kEmbeddedExtensionSource =
5044 "function Ret54321(){return 54321;}~~@@$"
5045 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5046static const int kEmbeddedExtensionSourceValidLen = 34;
5047
5048
5049THREADED_TEST(ExtensionMissingSourceLength) {
5050 v8::HandleScope handle_scope;
5051 v8::RegisterExtension(new Extension("srclentest_fail",
5052 kEmbeddedExtensionSource));
5053 const char* extension_names[] = { "srclentest_fail" };
5054 v8::ExtensionConfiguration extensions(1, extension_names);
5055 v8::Handle<Context> context = Context::New(&extensions);
5056 CHECK_EQ(0, *context);
5057}
5058
5059
5060THREADED_TEST(ExtensionWithSourceLength) {
5061 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5062 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
5063 v8::HandleScope handle_scope;
5064 i::ScopedVector<char> extension_name(32);
5065 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
5066 v8::RegisterExtension(new Extension(extension_name.start(),
5067 kEmbeddedExtensionSource, 0, 0,
5068 source_len));
5069 const char* extension_names[1] = { extension_name.start() };
5070 v8::ExtensionConfiguration extensions(1, extension_names);
5071 v8::Handle<Context> context = Context::New(&extensions);
5072 if (source_len == kEmbeddedExtensionSourceValidLen) {
5073 Context::Scope lock(context);
5074 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
5075 CHECK_EQ(v8::Integer::New(54321), result);
5076 } else {
5077 // Anything but exactly the right length should fail to compile.
5078 CHECK_EQ(0, *context);
5079 }
5080 }
5081}
5082
5083
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005084static const char* kEvalExtensionSource1 =
5085 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005086 " var x = 42;"
5087 " return eval('x');"
5088 "}";
5089
5090
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005091static const char* kEvalExtensionSource2 =
5092 "(function() {"
5093 " var x = 42;"
5094 " function e() {"
5095 " return eval('x');"
5096 " }"
5097 " this.UseEval2 = e;"
5098 "})()";
5099
5100
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005101THREADED_TEST(UseEvalFromExtension) {
5102 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005103 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
5104 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
5105 const char* extension_names[] = { "evaltest1", "evaltest2" };
5106 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005107 v8::Handle<Context> context = Context::New(&extensions);
5108 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005109 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
5110 CHECK_EQ(result, v8::Integer::New(42));
5111 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005112 CHECK_EQ(result, v8::Integer::New(42));
5113}
5114
5115
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005116static const char* kWithExtensionSource1 =
5117 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005118 " var x = 42;"
5119 " with({x:87}) { return x; }"
5120 "}";
5121
5122
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005123
5124static const char* kWithExtensionSource2 =
5125 "(function() {"
5126 " var x = 42;"
5127 " function e() {"
5128 " with ({x:87}) { return x; }"
5129 " }"
5130 " this.UseWith2 = e;"
5131 "})()";
5132
5133
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005134THREADED_TEST(UseWithFromExtension) {
5135 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005136 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
5137 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
5138 const char* extension_names[] = { "withtest1", "withtest2" };
5139 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005140 v8::Handle<Context> context = Context::New(&extensions);
5141 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005142 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
5143 CHECK_EQ(result, v8::Integer::New(87));
5144 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005145 CHECK_EQ(result, v8::Integer::New(87));
5146}
5147
5148
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005149THREADED_TEST(AutoExtensions) {
5150 v8::HandleScope handle_scope;
5151 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
5152 extension->set_auto_enable(true);
5153 v8::RegisterExtension(extension);
5154 v8::Handle<Context> context = Context::New();
5155 Context::Scope lock(context);
5156 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5157 CHECK_EQ(result, v8::Integer::New(4));
5158}
5159
5160
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005161static const char* kSyntaxErrorInExtensionSource =
5162 "[";
5163
5164
5165// Test that a syntax error in an extension does not cause a fatal
5166// error but results in an empty context.
5167THREADED_TEST(SyntaxErrorExtensions) {
5168 v8::HandleScope handle_scope;
5169 v8::RegisterExtension(new Extension("syntaxerror",
5170 kSyntaxErrorInExtensionSource));
5171 const char* extension_names[] = { "syntaxerror" };
5172 v8::ExtensionConfiguration extensions(1, extension_names);
5173 v8::Handle<Context> context = Context::New(&extensions);
5174 CHECK(context.IsEmpty());
5175}
5176
5177
5178static const char* kExceptionInExtensionSource =
5179 "throw 42";
5180
5181
5182// Test that an exception when installing an extension does not cause
5183// a fatal error but results in an empty context.
5184THREADED_TEST(ExceptionExtensions) {
5185 v8::HandleScope handle_scope;
5186 v8::RegisterExtension(new Extension("exception",
5187 kExceptionInExtensionSource));
5188 const char* extension_names[] = { "exception" };
5189 v8::ExtensionConfiguration extensions(1, extension_names);
5190 v8::Handle<Context> context = Context::New(&extensions);
5191 CHECK(context.IsEmpty());
5192}
5193
5194
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005195static const char* kNativeCallInExtensionSource =
5196 "function call_runtime_last_index_of(x) {"
5197 " return %StringLastIndexOf(x, 'bob', 10);"
5198 "}";
5199
5200
5201static const char* kNativeCallTest =
5202 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
5203
5204// Test that a native runtime calls are supported in extensions.
5205THREADED_TEST(NativeCallInExtensions) {
5206 v8::HandleScope handle_scope;
5207 v8::RegisterExtension(new Extension("nativecall",
5208 kNativeCallInExtensionSource));
5209 const char* extension_names[] = { "nativecall" };
5210 v8::ExtensionConfiguration extensions(1, extension_names);
5211 v8::Handle<Context> context = Context::New(&extensions);
5212 Context::Scope lock(context);
5213 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
5214 CHECK_EQ(result, v8::Integer::New(3));
5215}
5216
5217
whesse@chromium.org7b260152011-06-20 15:33:18 +00005218class NativeFunctionExtension : public Extension {
5219 public:
5220 NativeFunctionExtension(const char* name,
5221 const char* source,
5222 v8::InvocationCallback fun = &Echo)
5223 : Extension(name, source),
5224 function_(fun) { }
5225
5226 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5227 v8::Handle<v8::String> name) {
5228 return v8::FunctionTemplate::New(function_);
5229 }
5230
5231 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
5232 if (args.Length() >= 1) return (args[0]);
5233 return v8::Undefined();
5234 }
5235 private:
5236 v8::InvocationCallback function_;
5237};
5238
5239
5240THREADED_TEST(NativeFunctionDeclaration) {
5241 v8::HandleScope handle_scope;
5242 const char* name = "nativedecl";
5243 v8::RegisterExtension(new NativeFunctionExtension(name,
5244 "native function foo();"));
5245 const char* extension_names[] = { name };
5246 v8::ExtensionConfiguration extensions(1, extension_names);
5247 v8::Handle<Context> context = Context::New(&extensions);
5248 Context::Scope lock(context);
5249 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
5250 CHECK_EQ(result, v8::Integer::New(42));
5251}
5252
5253
5254THREADED_TEST(NativeFunctionDeclarationError) {
5255 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005256 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005257 // Syntax error in extension code.
5258 v8::RegisterExtension(new NativeFunctionExtension(name,
5259 "native\nfunction foo();"));
5260 const char* extension_names[] = { name };
5261 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005262 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005263 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005264}
5265
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005266
whesse@chromium.org7b260152011-06-20 15:33:18 +00005267THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
5268 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005269 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005270 // Syntax error in extension code - escape code in "native" means that
5271 // it's not treated as a keyword.
5272 v8::RegisterExtension(new NativeFunctionExtension(
5273 name,
5274 "nativ\\u0065 function foo();"));
5275 const char* extension_names[] = { name };
5276 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005277 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005278 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005279}
5280
5281
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005282static void CheckDependencies(const char* name, const char* expected) {
5283 v8::HandleScope handle_scope;
5284 v8::ExtensionConfiguration config(1, &name);
5285 LocalContext context(&config);
5286 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5287}
5288
5289
5290/*
5291 * Configuration:
5292 *
5293 * /-- B <--\
5294 * A <- -- D <-- E
5295 * \-- C <--/
5296 */
5297THREADED_TEST(ExtensionDependency) {
5298 static const char* kEDeps[] = { "D" };
5299 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5300 static const char* kDDeps[] = { "B", "C" };
5301 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5302 static const char* kBCDeps[] = { "A" };
5303 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5304 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5305 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5306 CheckDependencies("A", "undefinedA");
5307 CheckDependencies("B", "undefinedAB");
5308 CheckDependencies("C", "undefinedAC");
5309 CheckDependencies("D", "undefinedABCD");
5310 CheckDependencies("E", "undefinedABCDE");
5311 v8::HandleScope handle_scope;
5312 static const char* exts[2] = { "C", "E" };
5313 v8::ExtensionConfiguration config(2, exts);
5314 LocalContext context(&config);
5315 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5316}
5317
5318
5319static const char* kExtensionTestScript =
5320 "native function A();"
5321 "native function B();"
5322 "native function C();"
5323 "function Foo(i) {"
5324 " if (i == 0) return A();"
5325 " if (i == 1) return B();"
5326 " if (i == 2) return C();"
5327 "}";
5328
5329
5330static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5331 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005332 if (args.IsConstructCall()) {
5333 args.This()->Set(v8_str("data"), args.Data());
5334 return v8::Null();
5335 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005336 return args.Data();
5337}
5338
5339
5340class FunctionExtension : public Extension {
5341 public:
5342 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5343 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5344 v8::Handle<String> name);
5345};
5346
5347
5348static int lookup_count = 0;
5349v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5350 v8::Handle<String> name) {
5351 lookup_count++;
5352 if (name->Equals(v8_str("A"))) {
5353 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5354 } else if (name->Equals(v8_str("B"))) {
5355 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5356 } else if (name->Equals(v8_str("C"))) {
5357 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5358 } else {
5359 return v8::Handle<v8::FunctionTemplate>();
5360 }
5361}
5362
5363
5364THREADED_TEST(FunctionLookup) {
5365 v8::RegisterExtension(new FunctionExtension());
5366 v8::HandleScope handle_scope;
5367 static const char* exts[1] = { "functiontest" };
5368 v8::ExtensionConfiguration config(1, exts);
5369 LocalContext context(&config);
5370 CHECK_EQ(3, lookup_count);
5371 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5372 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5373 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5374}
5375
5376
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005377THREADED_TEST(NativeFunctionConstructCall) {
5378 v8::RegisterExtension(new FunctionExtension());
5379 v8::HandleScope handle_scope;
5380 static const char* exts[1] = { "functiontest" };
5381 v8::ExtensionConfiguration config(1, exts);
5382 LocalContext context(&config);
5383 for (int i = 0; i < 10; i++) {
5384 // Run a few times to ensure that allocation of objects doesn't
5385 // change behavior of a constructor function.
5386 CHECK_EQ(v8::Integer::New(8),
5387 Script::Compile(v8_str("(new A()).data"))->Run());
5388 CHECK_EQ(v8::Integer::New(7),
5389 Script::Compile(v8_str("(new B()).data"))->Run());
5390 CHECK_EQ(v8::Integer::New(6),
5391 Script::Compile(v8_str("(new C()).data"))->Run());
5392 }
5393}
5394
5395
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005396static const char* last_location;
5397static const char* last_message;
5398void StoringErrorCallback(const char* location, const char* message) {
5399 if (last_location == NULL) {
5400 last_location = location;
5401 last_message = message;
5402 }
5403}
5404
5405
5406// ErrorReporting creates a circular extensions configuration and
5407// tests that the fatal error handler gets called. This renders V8
5408// unusable and therefore this test cannot be run in parallel.
5409TEST(ErrorReporting) {
5410 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
5411 static const char* aDeps[] = { "B" };
5412 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5413 static const char* bDeps[] = { "A" };
5414 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5415 last_location = NULL;
5416 v8::ExtensionConfiguration config(1, bDeps);
5417 v8::Handle<Context> context = Context::New(&config);
5418 CHECK(context.IsEmpty());
5419 CHECK_NE(last_location, NULL);
5420}
5421
5422
ager@chromium.org7c537e22008-10-16 08:43:32 +00005423static const char* js_code_causing_huge_string_flattening =
5424 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00005425 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00005426 " str = str + str;"
5427 "}"
5428 "str.match(/X/);";
5429
5430
5431void OOMCallback(const char* location, const char* message) {
5432 exit(0);
5433}
5434
5435
5436TEST(RegexpOutOfMemory) {
5437 // Execute a script that causes out of memory when flattening a string.
5438 v8::HandleScope scope;
5439 v8::V8::SetFatalErrorHandler(OOMCallback);
5440 LocalContext context;
5441 Local<Script> script =
5442 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5443 last_location = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005444 script->Run();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005445
5446 CHECK(false); // Should not return.
5447}
5448
5449
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005450static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5451 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005452 CHECK(message->GetScriptResourceName()->IsUndefined());
5453 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005454 message->GetLineNumber();
5455 message->GetSourceLine();
5456}
5457
5458
5459THREADED_TEST(ErrorWithMissingScriptInfo) {
5460 v8::HandleScope scope;
5461 LocalContext context;
5462 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5463 Script::Compile(v8_str("throw Error()"))->Run();
5464 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5465}
5466
5467
5468int global_index = 0;
5469
5470class Snorkel {
5471 public:
5472 Snorkel() { index_ = global_index++; }
5473 int index_;
5474};
5475
5476class Whammy {
5477 public:
5478 Whammy() {
5479 cursor_ = 0;
5480 }
5481 ~Whammy() {
5482 script_.Dispose();
5483 }
5484 v8::Handle<Script> getScript() {
5485 if (script_.IsEmpty())
5486 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5487 return Local<Script>(*script_);
5488 }
5489
5490 public:
5491 static const int kObjectCount = 256;
5492 int cursor_;
5493 v8::Persistent<v8::Object> objects_[kObjectCount];
5494 v8::Persistent<Script> script_;
5495};
5496
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005497static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005498 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5499 delete snorkel;
5500 obj.ClearWeak();
5501}
5502
5503v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5504 const AccessorInfo& info) {
5505 Whammy* whammy =
5506 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5507
5508 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5509
5510 v8::Handle<v8::Object> obj = v8::Object::New();
5511 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5512 if (!prev.IsEmpty()) {
5513 prev->Set(v8_str("next"), obj);
5514 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5515 whammy->objects_[whammy->cursor_].Clear();
5516 }
5517 whammy->objects_[whammy->cursor_] = global;
5518 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5519 return whammy->getScript()->Run();
5520}
5521
5522THREADED_TEST(WeakReference) {
5523 v8::HandleScope handle_scope;
5524 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005525 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005526 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5527 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005528 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005529 const char* extension_list[] = { "v8/gc" };
5530 v8::ExtensionConfiguration extensions(1, extension_list);
5531 v8::Persistent<Context> context = Context::New(&extensions);
5532 Context::Scope context_scope(context);
5533
5534 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5535 context->Global()->Set(v8_str("whammy"), interceptor);
5536 const char* code =
5537 "var last;"
5538 "for (var i = 0; i < 10000; i++) {"
5539 " var obj = whammy.length;"
5540 " if (last) last.next = obj;"
5541 " last = obj;"
5542 "}"
5543 "gc();"
5544 "4";
5545 v8::Handle<Value> result = CompileRun(code);
5546 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005547 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005548 context.Dispose();
5549}
5550
5551
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005552static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005553 obj.Dispose();
5554 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005555 *(reinterpret_cast<bool*>(data)) = true;
5556}
5557
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005558
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005559THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005560 v8::Persistent<Context> context = Context::New();
5561 Context::Scope context_scope(context);
5562
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005563 v8::Persistent<v8::Object> object_a, object_b;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005564
5565 {
5566 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005567 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005568 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005569 }
5570
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005571 v8::Isolate* isolate = v8::Isolate::GetCurrent();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005572 bool object_a_disposed = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005573 bool object_b_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005574 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005575 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005576 CHECK(!object_a.IsIndependent());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005577 CHECK(!object_b.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005578 object_a.MarkIndependent();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005579 object_b.MarkIndependent(isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005580 CHECK(object_a.IsIndependent());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005581 CHECK(object_b.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005582 HEAP->PerformScavenge();
5583 CHECK(object_a_disposed);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005584 CHECK(object_b_disposed);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005585}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005586
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005587
5588static void InvokeScavenge() {
5589 HEAP->PerformScavenge();
5590}
5591
5592
5593static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005594 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005595}
5596
5597
5598static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5599 obj.Dispose();
5600 obj.Clear();
5601 *(reinterpret_cast<bool*>(data)) = true;
5602 InvokeScavenge();
5603}
5604
5605
5606static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5607 obj.Dispose();
5608 obj.Clear();
5609 *(reinterpret_cast<bool*>(data)) = true;
5610 InvokeMarkSweep();
5611}
5612
5613
5614THREADED_TEST(GCFromWeakCallbacks) {
5615 v8::Persistent<Context> context = Context::New();
5616 Context::Scope context_scope(context);
5617
5618 static const int kNumberOfGCTypes = 2;
5619 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5620 {&ForceScavenge, &ForceMarkSweep};
5621
5622 typedef void (*GCInvoker)();
5623 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5624
5625 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5626 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5627 v8::Persistent<v8::Object> object;
5628 {
5629 v8::HandleScope handle_scope;
5630 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5631 }
5632 bool disposed = false;
5633 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5634 object.MarkIndependent();
5635 invoke_gc[outer_gc]();
5636 CHECK(disposed);
5637 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005638 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005639}
5640
5641
5642static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5643 obj.ClearWeak();
5644 *(reinterpret_cast<bool*>(data)) = true;
5645}
5646
5647
5648THREADED_TEST(IndependentHandleRevival) {
5649 v8::Persistent<Context> context = Context::New();
5650 Context::Scope context_scope(context);
5651
5652 v8::Persistent<v8::Object> object;
5653 {
5654 v8::HandleScope handle_scope;
5655 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5656 object->Set(v8_str("x"), v8::Integer::New(1));
5657 v8::Local<String> y_str = v8_str("y");
5658 object->Set(y_str, y_str);
5659 }
5660 bool revived = false;
5661 object.MakeWeak(&revived, &RevivingCallback);
5662 object.MarkIndependent();
5663 HEAP->PerformScavenge();
5664 CHECK(revived);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00005665 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005666 {
5667 v8::HandleScope handle_scope;
5668 v8::Local<String> y_str = v8_str("y");
5669 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5670 CHECK(object->Get(y_str)->Equals(y_str));
5671 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005672}
5673
5674
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005675v8::Handle<Function> args_fun;
5676
5677
5678static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5679 ApiTestFuzzer::Fuzz();
5680 CHECK_EQ(args_fun, args.Callee());
5681 CHECK_EQ(3, args.Length());
5682 CHECK_EQ(v8::Integer::New(1), args[0]);
5683 CHECK_EQ(v8::Integer::New(2), args[1]);
5684 CHECK_EQ(v8::Integer::New(3), args[2]);
5685 CHECK_EQ(v8::Undefined(), args[3]);
5686 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005687 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005688 return v8::Undefined();
5689}
5690
5691
5692THREADED_TEST(Arguments) {
5693 v8::HandleScope scope;
5694 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5695 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5696 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005697 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005698 v8_compile("f(1, 2, 3)")->Run();
5699}
5700
5701
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005702static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5703 const AccessorInfo&) {
5704 return v8::Handle<Value>();
5705}
5706
5707
5708static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5709 const AccessorInfo&) {
5710 return v8::Handle<Value>();
5711}
5712
5713
5714static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5715 const AccessorInfo&) {
5716 if (!name->Equals(v8_str("foo"))) {
5717 return v8::Handle<v8::Boolean>(); // not intercepted
5718 }
5719
5720 return v8::False(); // intercepted, and don't delete the property
5721}
5722
5723
5724static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5725 if (index != 2) {
5726 return v8::Handle<v8::Boolean>(); // not intercepted
5727 }
5728
5729 return v8::False(); // intercepted, and don't delete the property
5730}
5731
5732
5733THREADED_TEST(Deleter) {
5734 v8::HandleScope scope;
5735 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5736 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5737 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5738 LocalContext context;
5739 context->Global()->Set(v8_str("k"), obj->NewInstance());
5740 CompileRun(
5741 "k.foo = 'foo';"
5742 "k.bar = 'bar';"
5743 "k[2] = 2;"
5744 "k[4] = 4;");
5745 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5746 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5747
5748 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5749 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5750
5751 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5752 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5753
5754 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5755 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5756}
5757
5758
5759static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5760 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005761 if (name->Equals(v8_str("foo")) ||
5762 name->Equals(v8_str("bar")) ||
5763 name->Equals(v8_str("baz"))) {
5764 return v8::Undefined();
5765 }
5766 return v8::Handle<Value>();
5767}
5768
5769
5770static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5771 ApiTestFuzzer::Fuzz();
5772 if (index == 0 || index == 1) return v8::Undefined();
5773 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005774}
5775
5776
5777static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5778 ApiTestFuzzer::Fuzz();
5779 v8::Handle<v8::Array> result = v8::Array::New(3);
5780 result->Set(v8::Integer::New(0), v8_str("foo"));
5781 result->Set(v8::Integer::New(1), v8_str("bar"));
5782 result->Set(v8::Integer::New(2), v8_str("baz"));
5783 return result;
5784}
5785
5786
5787static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5788 ApiTestFuzzer::Fuzz();
5789 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005790 result->Set(v8::Integer::New(0), v8_str("0"));
5791 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005792 return result;
5793}
5794
5795
5796THREADED_TEST(Enumerators) {
5797 v8::HandleScope scope;
5798 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5799 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005800 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005801 LocalContext context;
5802 context->Global()->Set(v8_str("k"), obj->NewInstance());
5803 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005804 "k[10] = 0;"
5805 "k.a = 0;"
5806 "k[5] = 0;"
5807 "k.b = 0;"
5808 "k[4294967295] = 0;"
5809 "k.c = 0;"
5810 "k[4294967296] = 0;"
5811 "k.d = 0;"
5812 "k[140000] = 0;"
5813 "k.e = 0;"
5814 "k[30000000000] = 0;"
5815 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005816 "var result = [];"
5817 "for (var prop in k) {"
5818 " result.push(prop);"
5819 "}"
5820 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005821 // Check that we get all the property names returned including the
5822 // ones from the enumerators in the right order: indexed properties
5823 // in numerical order, indexed interceptor properties, named
5824 // properties in insertion order, named interceptor properties.
5825 // This order is not mandated by the spec, so this test is just
5826 // documenting our behavior.
5827 CHECK_EQ(17, result->Length());
5828 // Indexed properties in numerical order.
5829 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5830 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5831 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5832 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5833 // Indexed interceptor properties in the order they are returned
5834 // from the enumerator interceptor.
5835 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5836 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5837 // Named properties in insertion order.
5838 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5839 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5840 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5841 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5842 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5843 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5844 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5845 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5846 // Named interceptor properties.
5847 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5848 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5849 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005850}
5851
5852
5853int p_getter_count;
5854int p_getter_count2;
5855
5856
5857static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5858 ApiTestFuzzer::Fuzz();
5859 p_getter_count++;
5860 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5861 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5862 if (name->Equals(v8_str("p1"))) {
5863 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5864 } else if (name->Equals(v8_str("p2"))) {
5865 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5866 } else if (name->Equals(v8_str("p3"))) {
5867 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5868 } else if (name->Equals(v8_str("p4"))) {
5869 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5870 }
5871 return v8::Undefined();
5872}
5873
5874
5875static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5876 ApiTestFuzzer::Fuzz();
5877 LocalContext context;
5878 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5879 CompileRun(
5880 "o1.__proto__ = { };"
5881 "var o2 = { __proto__: o1 };"
5882 "var o3 = { __proto__: o2 };"
5883 "var o4 = { __proto__: o3 };"
5884 "for (var i = 0; i < 10; i++) o4.p4;"
5885 "for (var i = 0; i < 10; i++) o3.p3;"
5886 "for (var i = 0; i < 10; i++) o2.p2;"
5887 "for (var i = 0; i < 10; i++) o1.p1;");
5888}
5889
5890
5891static v8::Handle<Value> PGetter2(Local<String> name,
5892 const AccessorInfo& info) {
5893 ApiTestFuzzer::Fuzz();
5894 p_getter_count2++;
5895 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5896 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5897 if (name->Equals(v8_str("p1"))) {
5898 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5899 } else if (name->Equals(v8_str("p2"))) {
5900 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5901 } else if (name->Equals(v8_str("p3"))) {
5902 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5903 } else if (name->Equals(v8_str("p4"))) {
5904 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5905 }
5906 return v8::Undefined();
5907}
5908
5909
5910THREADED_TEST(GetterHolders) {
5911 v8::HandleScope scope;
5912 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5913 obj->SetAccessor(v8_str("p1"), PGetter);
5914 obj->SetAccessor(v8_str("p2"), PGetter);
5915 obj->SetAccessor(v8_str("p3"), PGetter);
5916 obj->SetAccessor(v8_str("p4"), PGetter);
5917 p_getter_count = 0;
5918 RunHolderTest(obj);
5919 CHECK_EQ(40, p_getter_count);
5920}
5921
5922
5923THREADED_TEST(PreInterceptorHolders) {
5924 v8::HandleScope scope;
5925 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5926 obj->SetNamedPropertyHandler(PGetter2);
5927 p_getter_count2 = 0;
5928 RunHolderTest(obj);
5929 CHECK_EQ(40, p_getter_count2);
5930}
5931
5932
5933THREADED_TEST(ObjectInstantiation) {
5934 v8::HandleScope scope;
5935 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5936 templ->SetAccessor(v8_str("t"), PGetter2);
5937 LocalContext context;
5938 context->Global()->Set(v8_str("o"), templ->NewInstance());
5939 for (int i = 0; i < 100; i++) {
5940 v8::HandleScope inner_scope;
5941 v8::Handle<v8::Object> obj = templ->NewInstance();
5942 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5943 context->Global()->Set(v8_str("o2"), obj);
5944 v8::Handle<Value> value =
5945 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5946 CHECK_EQ(v8::True(), value);
5947 context->Global()->Set(v8_str("o"), obj);
5948 }
5949}
5950
5951
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005952static int StrCmp16(uint16_t* a, uint16_t* b) {
5953 while (true) {
5954 if (*a == 0 && *b == 0) return 0;
5955 if (*a != *b) return 0 + *a - *b;
5956 a++;
5957 b++;
5958 }
5959}
5960
5961
5962static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5963 while (true) {
5964 if (n-- == 0) return 0;
5965 if (*a == 0 && *b == 0) return 0;
5966 if (*a != *b) return 0 + *a - *b;
5967 a++;
5968 b++;
5969 }
5970}
5971
5972
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005973int GetUtf8Length(Handle<String> str) {
5974 int len = str->Utf8Length();
5975 if (len < 0) {
5976 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5977 i::FlattenString(istr);
5978 len = str->Utf8Length();
5979 }
5980 return len;
5981}
5982
5983
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005984THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005985 LocalContext context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005986 v8::HandleScope scope;
5987 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005988 // abc<Icelandic eth><Unicode snowman>.
5989 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005990 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005991 const int kStride = 4; // Must match stride in for loops in JS below.
5992 CompileRun(
5993 "var left = '';"
5994 "for (var i = 0; i < 0xd800; i += 4) {"
5995 " left = left + String.fromCharCode(i);"
5996 "}");
5997 CompileRun(
5998 "var right = '';"
5999 "for (var i = 0; i < 0xd800; i += 4) {"
6000 " right = String.fromCharCode(i) + right;"
6001 "}");
6002 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6003 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
6004 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006005
6006 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006007 CHECK_EQ(0xd800 / kStride, left_tree->Length());
6008 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006009
6010 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006011 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006012 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006013 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006014 int charlen;
6015
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006016 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006017 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006018 CHECK_EQ(9, len);
6019 CHECK_EQ(5, charlen);
6020 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006021
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006022 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006023 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006024 CHECK_EQ(8, len);
6025 CHECK_EQ(5, charlen);
6026 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006027
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006028 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006029 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006030 CHECK_EQ(5, len);
6031 CHECK_EQ(4, charlen);
6032 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006033
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006034 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006035 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006036 CHECK_EQ(5, len);
6037 CHECK_EQ(4, charlen);
6038 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006039
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006040 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006041 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006042 CHECK_EQ(5, len);
6043 CHECK_EQ(4, charlen);
6044 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006045
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006046 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006047 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006048 CHECK_EQ(3, len);
6049 CHECK_EQ(3, charlen);
6050 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006051
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006052 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006053 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006054 CHECK_EQ(3, len);
6055 CHECK_EQ(3, charlen);
6056 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006058 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006059 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006060 CHECK_EQ(2, len);
6061 CHECK_EQ(2, charlen);
6062 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006063
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006064 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006065 len = GetUtf8Length(left_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006066 int utf8_expected =
6067 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
6068 CHECK_EQ(utf8_expected, len);
6069 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6070 CHECK_EQ(utf8_expected, len);
6071 CHECK_EQ(0xd800 / kStride, charlen);
6072 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
6073 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
6074 CHECK_EQ(0xc0 - kStride,
6075 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
6076 CHECK_EQ(1, utf8buf[utf8_expected]);
6077
6078 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006079 len = GetUtf8Length(right_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006080 CHECK_EQ(utf8_expected, len);
6081 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6082 CHECK_EQ(utf8_expected, len);
6083 CHECK_EQ(0xd800 / kStride, charlen);
6084 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
6085 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
6086 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
6087 CHECK_EQ(1, utf8buf[utf8_expected]);
6088
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006089 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006090 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006091 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006092 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006093 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006094 CHECK_EQ(5, len);
6095 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006096 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006097 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006098
6099 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006100 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006101 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006102 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006103 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006104 CHECK_EQ(4, len);
6105 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006106 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006107 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006108
6109 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006110 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006111 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006112 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006113 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006114 CHECK_EQ(5, len);
6115 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006116 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006117 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006118
6119 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006120 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006121 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006122 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006123 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006124 CHECK_EQ(5, len);
6125 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006126 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006127 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006128
6129 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006130 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006131 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006132 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006133 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006134 CHECK_EQ(1, len);
6135 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006136 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006137 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006138
6139 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006140 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006141 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006142 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006143 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006144 CHECK_EQ(1, len);
6145 CHECK_EQ(0, strcmp("e", buf));
6146 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006147
6148 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006149 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006150 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006151 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006152 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006153 CHECK_EQ(1, len);
6154 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006155 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006156 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006157
6158 memset(buf, 0x1, sizeof(buf));
6159 memset(wbuf, 0x1, sizeof(wbuf));
6160 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006161 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006162 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006163 CHECK_EQ(1, len);
6164 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006165 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006166 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006167
6168 memset(wbuf, 0x1, sizeof(wbuf));
6169 wbuf[5] = 'X';
6170 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
6171 CHECK_EQ(5, len);
6172 CHECK_EQ('X', wbuf[5]);
6173 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
6174 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6175 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
6176 CHECK_NE(0, StrCmp16(answer8b, wbuf));
6177 wbuf[5] = '\0';
6178 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
6179
6180 memset(buf, 0x1, sizeof(buf));
6181 buf[5] = 'X';
6182 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
6183 CHECK_EQ(5, len);
6184 CHECK_EQ('X', buf[5]);
6185 CHECK_EQ(0, strncmp("abcde", buf, 5));
6186 CHECK_NE(0, strcmp("abcde", buf));
6187 buf[5] = '\0';
6188 CHECK_EQ(0, strcmp("abcde", buf));
6189
6190 memset(utf8buf, 0x1, sizeof(utf8buf));
6191 utf8buf[8] = 'X';
6192 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6193 String::NO_NULL_TERMINATION);
6194 CHECK_EQ(8, len);
6195 CHECK_EQ('X', utf8buf[8]);
6196 CHECK_EQ(5, charlen);
6197 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
6198 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6199 utf8buf[8] = '\0';
6200 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006201
6202 memset(utf8buf, 0x1, sizeof(utf8buf));
6203 utf8buf[5] = 'X';
6204 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6205 String::NO_NULL_TERMINATION);
6206 CHECK_EQ(5, len);
6207 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
6208 CHECK_EQ(5, charlen);
6209 utf8buf[5] = '\0';
6210 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
6211
6212 memset(buf, 0x1, sizeof(buf));
6213 len = str3->WriteAscii(buf);
6214 CHECK_EQ(7, len);
6215 CHECK_EQ(0, strcmp("abc def", buf));
6216
6217 memset(buf, 0x1, sizeof(buf));
6218 len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
6219 CHECK_EQ(7, len);
6220 CHECK_EQ(0, strcmp("abc", buf));
6221 CHECK_EQ(0, buf[3]);
6222 CHECK_EQ(0, strcmp("def", buf + 4));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006223
6224 CHECK_EQ(0, str->WriteAscii(NULL, 0, 0, String::NO_NULL_TERMINATION));
6225 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
6226 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006227}
6228
6229
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006230static void Utf16Helper(
6231 LocalContext& context,
6232 const char* name,
6233 const char* lengths_name,
6234 int len) {
6235 Local<v8::Array> a =
6236 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6237 Local<v8::Array> alens =
6238 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6239 for (int i = 0; i < len; i++) {
6240 Local<v8::String> string =
6241 Local<v8::String>::Cast(a->Get(i));
6242 Local<v8::Number> expected_len =
6243 Local<v8::Number>::Cast(alens->Get(i));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006244#ifndef ENABLE_LATIN_1
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006245 CHECK_EQ(expected_len->Value() != string->Length(),
6246 string->MayContainNonAscii());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006247#endif
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006248 int length = GetUtf8Length(string);
6249 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
6250 }
6251}
6252
6253
6254static uint16_t StringGet(Handle<String> str, int index) {
6255 i::Handle<i::String> istring =
6256 v8::Utils::OpenHandle(String::Cast(*str));
6257 return istring->Get(index);
6258}
6259
6260
6261static void WriteUtf8Helper(
6262 LocalContext& context,
6263 const char* name,
6264 const char* lengths_name,
6265 int len) {
6266 Local<v8::Array> b =
6267 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6268 Local<v8::Array> alens =
6269 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6270 char buffer[1000];
6271 char buffer2[1000];
6272 for (int i = 0; i < len; i++) {
6273 Local<v8::String> string =
6274 Local<v8::String>::Cast(b->Get(i));
6275 Local<v8::Number> expected_len =
6276 Local<v8::Number>::Cast(alens->Get(i));
6277 int utf8_length = static_cast<int>(expected_len->Value());
6278 for (int j = utf8_length + 1; j >= 0; j--) {
6279 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6280 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6281 int nchars;
6282 int utf8_written =
6283 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6284 int utf8_written2 =
6285 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6286 CHECK_GE(utf8_length + 1, utf8_written);
6287 CHECK_GE(utf8_length, utf8_written2);
6288 for (int k = 0; k < utf8_written2; k++) {
6289 CHECK_EQ(buffer[k], buffer2[k]);
6290 }
6291 CHECK(nchars * 3 >= utf8_written - 1);
6292 CHECK(nchars <= utf8_written);
6293 if (j == utf8_length + 1) {
6294 CHECK_EQ(utf8_written2, utf8_length);
6295 CHECK_EQ(utf8_written2 + 1, utf8_written);
6296 }
6297 CHECK_EQ(buffer[utf8_written], 42);
6298 if (j > utf8_length) {
6299 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6300 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6301 Handle<String> roundtrip = v8_str(buffer);
6302 CHECK(roundtrip->Equals(string));
6303 } else {
6304 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6305 }
6306 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6307 if (nchars >= 2) {
6308 uint16_t trail = StringGet(string, nchars - 1);
6309 uint16_t lead = StringGet(string, nchars - 2);
6310 if (((lead & 0xfc00) == 0xd800) &&
6311 ((trail & 0xfc00) == 0xdc00)) {
6312 unsigned char u1 = buffer2[utf8_written2 - 4];
6313 unsigned char u2 = buffer2[utf8_written2 - 3];
6314 unsigned char u3 = buffer2[utf8_written2 - 2];
6315 unsigned char u4 = buffer2[utf8_written2 - 1];
6316 CHECK_EQ((u1 & 0xf8), 0xf0);
6317 CHECK_EQ((u2 & 0xc0), 0x80);
6318 CHECK_EQ((u3 & 0xc0), 0x80);
6319 CHECK_EQ((u4 & 0xc0), 0x80);
6320 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6321 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6322 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6323 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6324 CHECK_EQ((u1 & 0x3), c >> 18);
6325 }
6326 }
6327 }
6328 }
6329}
6330
6331
6332THREADED_TEST(Utf16) {
6333 LocalContext context;
6334 v8::HandleScope scope;
6335 CompileRun(
6336 "var pad = '01234567890123456789';"
6337 "var p = [];"
6338 "var plens = [20, 3, 3];"
6339 "p.push('01234567890123456789');"
6340 "var lead = 0xd800;"
6341 "var trail = 0xdc00;"
6342 "p.push(String.fromCharCode(0xd800));"
6343 "p.push(String.fromCharCode(0xdc00));"
6344 "var a = [];"
6345 "var b = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006346 "var c = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006347 "var alens = [];"
6348 "for (var i = 0; i < 3; i++) {"
6349 " p[1] = String.fromCharCode(lead++);"
6350 " for (var j = 0; j < 3; j++) {"
6351 " p[2] = String.fromCharCode(trail++);"
6352 " a.push(p[i] + p[j]);"
6353 " b.push(p[i] + p[j]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006354 " c.push(p[i] + p[j]);"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006355 " alens.push(plens[i] + plens[j]);"
6356 " }"
6357 "}"
6358 "alens[5] -= 2;" // Here the surrogate pairs match up.
6359 "var a2 = [];"
6360 "var b2 = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006361 "var c2 = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006362 "var a2lens = [];"
6363 "for (var m = 0; m < 9; m++) {"
6364 " for (var n = 0; n < 9; n++) {"
6365 " a2.push(a[m] + a[n]);"
6366 " b2.push(b[m] + b[n]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006367 " var newc = 'x' + c[m] + c[n] + 'y';"
6368 " c2.push(newc.substring(1, newc.length - 1));"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006369 " var utf = alens[m] + alens[n];" // And here.
6370 // The 'n's that start with 0xdc.. are 6-8
6371 // The 'm's that end with 0xd8.. are 1, 4 and 7
6372 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6373 " a2lens.push(utf);"
6374 " }"
6375 "}");
6376 Utf16Helper(context, "a", "alens", 9);
6377 Utf16Helper(context, "a2", "a2lens", 81);
6378 WriteUtf8Helper(context, "b", "alens", 9);
6379 WriteUtf8Helper(context, "b2", "a2lens", 81);
danno@chromium.org88aa0582012-03-23 15:11:57 +00006380 WriteUtf8Helper(context, "c2", "a2lens", 81);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006381}
6382
6383
6384static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6385 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6386 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6387 return *is1 == *is2;
6388}
6389
6390
6391static void SameSymbolHelper(const char* a, const char* b) {
6392 Handle<String> symbol1 = v8::String::NewSymbol(a);
6393 Handle<String> symbol2 = v8::String::NewSymbol(b);
6394 CHECK(SameSymbol(symbol1, symbol2));
6395}
6396
6397
6398THREADED_TEST(Utf16Symbol) {
6399 LocalContext context;
6400 v8::HandleScope scope;
6401
6402 Handle<String> symbol1 = v8::String::NewSymbol("abc");
6403 Handle<String> symbol2 = v8::String::NewSymbol("abc");
6404 CHECK(SameSymbol(symbol1, symbol2));
6405
6406 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6407 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6408 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6409 "\360\220\220\206"); // 4 byte encoding.
6410 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6411 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6412 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6413 "x\360\220\220\206"); // 4 byte encoding.
6414 CompileRun(
6415 "var sym0 = 'benedictus';"
6416 "var sym0b = 'S\303\270ren';"
6417 "var sym1 = '\355\240\201\355\260\207';"
6418 "var sym2 = '\360\220\220\210';"
6419 "var sym3 = 'x\355\240\201\355\260\207';"
6420 "var sym4 = 'x\360\220\220\210';"
6421 "if (sym1.length != 2) throw sym1;"
6422 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6423 "if (sym2.length != 2) throw sym2;"
6424 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6425 "if (sym3.length != 3) throw sym3;"
6426 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6427 "if (sym4.length != 3) throw sym4;"
6428 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6429 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6430 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6431 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6432 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6433 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6434 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6435 v8::Local<v8::Object> global = context->Global();
6436 Local<Value> s0 = global->Get(v8_str("sym0"));
6437 Local<Value> s0b = global->Get(v8_str("sym0b"));
6438 Local<Value> s1 = global->Get(v8_str("sym1"));
6439 Local<Value> s2 = global->Get(v8_str("sym2"));
6440 Local<Value> s3 = global->Get(v8_str("sym3"));
6441 Local<Value> s4 = global->Get(v8_str("sym4"));
6442 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6443 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6444 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6445 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6446 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6447 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6448}
6449
6450
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006451THREADED_TEST(ToArrayIndex) {
6452 v8::HandleScope scope;
6453 LocalContext context;
6454
6455 v8::Handle<String> str = v8_str("42");
6456 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6457 CHECK(!index.IsEmpty());
6458 CHECK_EQ(42.0, index->Uint32Value());
6459 str = v8_str("42asdf");
6460 index = str->ToArrayIndex();
6461 CHECK(index.IsEmpty());
6462 str = v8_str("-42");
6463 index = str->ToArrayIndex();
6464 CHECK(index.IsEmpty());
6465 str = v8_str("4294967295");
6466 index = str->ToArrayIndex();
6467 CHECK(!index.IsEmpty());
6468 CHECK_EQ(4294967295.0, index->Uint32Value());
6469 v8::Handle<v8::Number> num = v8::Number::New(1);
6470 index = num->ToArrayIndex();
6471 CHECK(!index.IsEmpty());
6472 CHECK_EQ(1.0, index->Uint32Value());
6473 num = v8::Number::New(-1);
6474 index = num->ToArrayIndex();
6475 CHECK(index.IsEmpty());
6476 v8::Handle<v8::Object> obj = v8::Object::New();
6477 index = obj->ToArrayIndex();
6478 CHECK(index.IsEmpty());
6479}
6480
6481
6482THREADED_TEST(ErrorConstruction) {
6483 v8::HandleScope scope;
6484 LocalContext context;
6485
6486 v8::Handle<String> foo = v8_str("foo");
6487 v8::Handle<String> message = v8_str("message");
6488 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6489 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006490 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006491 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6492 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006493 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006494 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6495 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006496 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006497 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6498 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006499 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006500 v8::Handle<Value> error = v8::Exception::Error(foo);
6501 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006502 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006503}
6504
6505
6506static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6507 ApiTestFuzzer::Fuzz();
6508 return v8_num(10);
6509}
6510
6511
6512static void YSetter(Local<String> name,
6513 Local<Value> value,
6514 const AccessorInfo& info) {
6515 if (info.This()->Has(name)) {
6516 info.This()->Delete(name);
6517 }
6518 info.This()->Set(name, value);
6519}
6520
6521
6522THREADED_TEST(DeleteAccessor) {
6523 v8::HandleScope scope;
6524 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6525 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6526 LocalContext context;
6527 v8::Handle<v8::Object> holder = obj->NewInstance();
6528 context->Global()->Set(v8_str("holder"), holder);
6529 v8::Handle<Value> result = CompileRun(
6530 "holder.y = 11; holder.y = 12; holder.y");
6531 CHECK_EQ(12, result->Uint32Value());
6532}
6533
6534
6535THREADED_TEST(TypeSwitch) {
6536 v8::HandleScope scope;
6537 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6538 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6539 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6540 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6541 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6542 LocalContext context;
6543 v8::Handle<v8::Object> obj0 = v8::Object::New();
6544 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6545 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6546 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6547 for (int i = 0; i < 10; i++) {
6548 CHECK_EQ(0, type_switch->match(obj0));
6549 CHECK_EQ(1, type_switch->match(obj1));
6550 CHECK_EQ(2, type_switch->match(obj2));
6551 CHECK_EQ(3, type_switch->match(obj3));
6552 CHECK_EQ(3, type_switch->match(obj3));
6553 CHECK_EQ(2, type_switch->match(obj2));
6554 CHECK_EQ(1, type_switch->match(obj1));
6555 CHECK_EQ(0, type_switch->match(obj0));
6556 }
6557}
6558
6559
6560// For use within the TestSecurityHandler() test.
6561static bool g_security_callback_result = false;
6562static bool NamedSecurityTestCallback(Local<v8::Object> global,
6563 Local<Value> name,
6564 v8::AccessType type,
6565 Local<Value> data) {
6566 // Always allow read access.
6567 if (type == v8::ACCESS_GET)
6568 return true;
6569
6570 // Sometimes allow other access.
6571 return g_security_callback_result;
6572}
6573
6574
6575static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6576 uint32_t key,
6577 v8::AccessType type,
6578 Local<Value> data) {
6579 // Always allow read access.
6580 if (type == v8::ACCESS_GET)
6581 return true;
6582
6583 // Sometimes allow other access.
6584 return g_security_callback_result;
6585}
6586
6587
6588static int trouble_nesting = 0;
6589static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6590 ApiTestFuzzer::Fuzz();
6591 trouble_nesting++;
6592
6593 // Call a JS function that throws an uncaught exception.
6594 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6595 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6596 arg_this->Get(v8_str("trouble_callee")) :
6597 arg_this->Get(v8_str("trouble_caller"));
6598 CHECK(trouble_callee->IsFunction());
6599 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6600}
6601
6602
6603static int report_count = 0;
6604static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6605 v8::Handle<Value>) {
6606 report_count++;
6607}
6608
6609
6610// Counts uncaught exceptions, but other tests running in parallel
6611// also have uncaught exceptions.
6612TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006613 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006614 v8::HandleScope scope;
6615 LocalContext env;
6616 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6617
6618 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6619 v8::Local<v8::Object> global = env->Global();
6620 global->Set(v8_str("trouble"), fun->GetFunction());
6621
6622 Script::Compile(v8_str("function trouble_callee() {"
6623 " var x = null;"
6624 " return x.foo;"
6625 "};"
6626 "function trouble_caller() {"
6627 " trouble();"
6628 "};"))->Run();
6629 Local<Value> trouble = global->Get(v8_str("trouble"));
6630 CHECK(trouble->IsFunction());
6631 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6632 CHECK(trouble_callee->IsFunction());
6633 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6634 CHECK(trouble_caller->IsFunction());
6635 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6636 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006637 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6638}
6639
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006640static const char* script_resource_name = "ExceptionInNativeScript.js";
6641static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6642 v8::Handle<Value>) {
6643 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6644 CHECK(!name_val.IsEmpty() && name_val->IsString());
6645 v8::String::AsciiValue name(message->GetScriptResourceName());
6646 CHECK_EQ(script_resource_name, *name);
6647 CHECK_EQ(3, message->GetLineNumber());
6648 v8::String::AsciiValue source_line(message->GetSourceLine());
6649 CHECK_EQ(" new o.foo();", *source_line);
6650}
6651
6652TEST(ExceptionInNativeScript) {
6653 v8::HandleScope scope;
6654 LocalContext env;
6655 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6656
6657 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6658 v8::Local<v8::Object> global = env->Global();
6659 global->Set(v8_str("trouble"), fun->GetFunction());
6660
6661 Script::Compile(v8_str("function trouble() {\n"
6662 " var o = {};\n"
6663 " new o.foo();\n"
6664 "};"), v8::String::New(script_resource_name))->Run();
6665 Local<Value> trouble = global->Get(v8_str("trouble"));
6666 CHECK(trouble->IsFunction());
6667 Function::Cast(*trouble)->Call(global, 0, NULL);
6668 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6669}
6670
ager@chromium.org8bb60582008-12-11 12:02:20 +00006671
6672TEST(CompilationErrorUsingTryCatchHandler) {
6673 v8::HandleScope scope;
6674 LocalContext env;
6675 v8::TryCatch try_catch;
6676 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6677 CHECK_NE(NULL, *try_catch.Exception());
6678 CHECK(try_catch.HasCaught());
6679}
6680
6681
6682TEST(TryCatchFinallyUsingTryCatchHandler) {
6683 v8::HandleScope scope;
6684 LocalContext env;
6685 v8::TryCatch try_catch;
6686 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6687 CHECK(!try_catch.HasCaught());
6688 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6689 CHECK(try_catch.HasCaught());
6690 try_catch.Reset();
6691 Script::Compile(v8_str("(function() {"
6692 "try { throw ''; } finally { return; }"
6693 "})()"))->Run();
6694 CHECK(!try_catch.HasCaught());
6695 Script::Compile(v8_str("(function()"
6696 " { try { throw ''; } finally { throw 0; }"
6697 "})()"))->Run();
6698 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006699}
6700
6701
6702// SecurityHandler can't be run twice
6703TEST(SecurityHandler) {
6704 v8::HandleScope scope0;
6705 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6706 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6707 IndexedSecurityTestCallback);
6708 // Create an environment
6709 v8::Persistent<Context> context0 =
6710 Context::New(NULL, global_template);
6711 context0->Enter();
6712
6713 v8::Handle<v8::Object> global0 = context0->Global();
6714 v8::Handle<Script> script0 = v8_compile("foo = 111");
6715 script0->Run();
6716 global0->Set(v8_str("0"), v8_num(999));
6717 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6718 CHECK_EQ(111, foo0->Int32Value());
6719 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6720 CHECK_EQ(999, z0->Int32Value());
6721
6722 // Create another environment, should fail security checks.
6723 v8::HandleScope scope1;
6724
6725 v8::Persistent<Context> context1 =
6726 Context::New(NULL, global_template);
6727 context1->Enter();
6728
6729 v8::Handle<v8::Object> global1 = context1->Global();
6730 global1->Set(v8_str("othercontext"), global0);
6731 // This set will fail the security check.
6732 v8::Handle<Script> script1 =
6733 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6734 script1->Run();
6735 // This read will pass the security check.
6736 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6737 CHECK_EQ(111, foo1->Int32Value());
6738 // This read will pass the security check.
6739 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6740 CHECK_EQ(999, z1->Int32Value());
6741
6742 // Create another environment, should pass security checks.
6743 { g_security_callback_result = true; // allow security handler to pass.
6744 v8::HandleScope scope2;
6745 LocalContext context2;
6746 v8::Handle<v8::Object> global2 = context2->Global();
6747 global2->Set(v8_str("othercontext"), global0);
6748 v8::Handle<Script> script2 =
6749 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6750 script2->Run();
6751 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6752 CHECK_EQ(333, foo2->Int32Value());
6753 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6754 CHECK_EQ(888, z2->Int32Value());
6755 }
6756
6757 context1->Exit();
6758 context1.Dispose();
6759
6760 context0->Exit();
6761 context0.Dispose();
6762}
6763
6764
6765THREADED_TEST(SecurityChecks) {
6766 v8::HandleScope handle_scope;
6767 LocalContext env1;
6768 v8::Persistent<Context> env2 = Context::New();
6769
6770 Local<Value> foo = v8_str("foo");
6771 Local<Value> bar = v8_str("bar");
6772
6773 // Set to the same domain.
6774 env1->SetSecurityToken(foo);
6775
6776 // Create a function in env1.
6777 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6778 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6779 CHECK(spy->IsFunction());
6780
6781 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006782 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006783 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6784 CHECK(spy2->IsFunction());
6785
6786 // Switch to env2 in the same domain and invoke spy on env2.
6787 {
6788 env2->SetSecurityToken(foo);
6789 // Enter env2
6790 Context::Scope scope_env2(env2);
6791 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6792 CHECK(result->IsFunction());
6793 }
6794
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006795 {
6796 env2->SetSecurityToken(bar);
6797 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006798
6799 // Call cross_domain_call, it should throw an exception
6800 v8::TryCatch try_catch;
6801 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6802 CHECK(try_catch.HasCaught());
6803 }
6804
6805 env2.Dispose();
6806}
6807
6808
6809// Regression test case for issue 1183439.
6810THREADED_TEST(SecurityChecksForPrototypeChain) {
6811 v8::HandleScope scope;
6812 LocalContext current;
6813 v8::Persistent<Context> other = Context::New();
6814
6815 // Change context to be able to get to the Object function in the
6816 // other context without hitting the security checks.
6817 v8::Local<Value> other_object;
6818 { Context::Scope scope(other);
6819 other_object = other->Global()->Get(v8_str("Object"));
6820 other->Global()->Set(v8_num(42), v8_num(87));
6821 }
6822
6823 current->Global()->Set(v8_str("other"), other->Global());
6824 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6825
6826 // Make sure the security check fails here and we get an undefined
6827 // result instead of getting the Object function. Repeat in a loop
6828 // to make sure to exercise the IC code.
6829 v8::Local<Script> access_other0 = v8_compile("other.Object");
6830 v8::Local<Script> access_other1 = v8_compile("other[42]");
6831 for (int i = 0; i < 5; i++) {
6832 CHECK(!access_other0->Run()->Equals(other_object));
6833 CHECK(access_other0->Run()->IsUndefined());
6834 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6835 CHECK(access_other1->Run()->IsUndefined());
6836 }
6837
6838 // Create an object that has 'other' in its prototype chain and make
6839 // sure we cannot access the Object function indirectly through
6840 // that. Repeat in a loop to make sure to exercise the IC code.
6841 v8_compile("function F() { };"
6842 "F.prototype = other;"
6843 "var f = new F();")->Run();
6844 v8::Local<Script> access_f0 = v8_compile("f.Object");
6845 v8::Local<Script> access_f1 = v8_compile("f[42]");
6846 for (int j = 0; j < 5; j++) {
6847 CHECK(!access_f0->Run()->Equals(other_object));
6848 CHECK(access_f0->Run()->IsUndefined());
6849 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6850 CHECK(access_f1->Run()->IsUndefined());
6851 }
6852
6853 // Now it gets hairy: Set the prototype for the other global object
6854 // to be the current global object. The prototype chain for 'f' now
6855 // goes through 'other' but ends up in the current global object.
6856 { Context::Scope scope(other);
6857 other->Global()->Set(v8_str("__proto__"), current->Global());
6858 }
6859 // Set a named and an index property on the current global
6860 // object. To force the lookup to go through the other global object,
6861 // the properties must not exist in the other global object.
6862 current->Global()->Set(v8_str("foo"), v8_num(100));
6863 current->Global()->Set(v8_num(99), v8_num(101));
6864 // Try to read the properties from f and make sure that the access
6865 // gets stopped by the security checks on the other global object.
6866 Local<Script> access_f2 = v8_compile("f.foo");
6867 Local<Script> access_f3 = v8_compile("f[99]");
6868 for (int k = 0; k < 5; k++) {
6869 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6870 CHECK(access_f2->Run()->IsUndefined());
6871 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6872 CHECK(access_f3->Run()->IsUndefined());
6873 }
6874 other.Dispose();
6875}
6876
6877
6878THREADED_TEST(CrossDomainDelete) {
6879 v8::HandleScope handle_scope;
6880 LocalContext env1;
6881 v8::Persistent<Context> env2 = Context::New();
6882
6883 Local<Value> foo = v8_str("foo");
6884 Local<Value> bar = v8_str("bar");
6885
6886 // Set to the same domain.
6887 env1->SetSecurityToken(foo);
6888 env2->SetSecurityToken(foo);
6889
6890 env1->Global()->Set(v8_str("prop"), v8_num(3));
6891 env2->Global()->Set(v8_str("env1"), env1->Global());
6892
6893 // Change env2 to a different domain and delete env1.prop.
6894 env2->SetSecurityToken(bar);
6895 {
6896 Context::Scope scope_env2(env2);
6897 Local<Value> result =
6898 Script::Compile(v8_str("delete env1.prop"))->Run();
6899 CHECK(result->IsFalse());
6900 }
6901
6902 // Check that env1.prop still exists.
6903 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6904 CHECK(v->IsNumber());
6905 CHECK_EQ(3, v->Int32Value());
6906
6907 env2.Dispose();
6908}
6909
6910
ager@chromium.org870a0b62008-11-04 11:43:05 +00006911THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6912 v8::HandleScope handle_scope;
6913 LocalContext env1;
6914 v8::Persistent<Context> env2 = Context::New();
6915
6916 Local<Value> foo = v8_str("foo");
6917 Local<Value> bar = v8_str("bar");
6918
6919 // Set to the same domain.
6920 env1->SetSecurityToken(foo);
6921 env2->SetSecurityToken(foo);
6922
6923 env1->Global()->Set(v8_str("prop"), v8_num(3));
6924 env2->Global()->Set(v8_str("env1"), env1->Global());
6925
6926 // env1.prop is enumerable in env2.
6927 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6928 {
6929 Context::Scope scope_env2(env2);
6930 Local<Value> result = Script::Compile(test)->Run();
6931 CHECK(result->IsTrue());
6932 }
6933
6934 // Change env2 to a different domain and test again.
6935 env2->SetSecurityToken(bar);
6936 {
6937 Context::Scope scope_env2(env2);
6938 Local<Value> result = Script::Compile(test)->Run();
6939 CHECK(result->IsFalse());
6940 }
6941
6942 env2.Dispose();
6943}
6944
6945
ager@chromium.org236ad962008-09-25 09:45:57 +00006946THREADED_TEST(CrossDomainForIn) {
6947 v8::HandleScope handle_scope;
6948 LocalContext env1;
6949 v8::Persistent<Context> env2 = Context::New();
6950
6951 Local<Value> foo = v8_str("foo");
6952 Local<Value> bar = v8_str("bar");
6953
6954 // Set to the same domain.
6955 env1->SetSecurityToken(foo);
6956 env2->SetSecurityToken(foo);
6957
6958 env1->Global()->Set(v8_str("prop"), v8_num(3));
6959 env2->Global()->Set(v8_str("env1"), env1->Global());
6960
6961 // Change env2 to a different domain and set env1's global object
6962 // as the __proto__ of an object in env2 and enumerate properties
6963 // in for-in. It shouldn't enumerate properties on env1's global
6964 // object.
6965 env2->SetSecurityToken(bar);
6966 {
6967 Context::Scope scope_env2(env2);
6968 Local<Value> result =
6969 CompileRun("(function(){var obj = {'__proto__':env1};"
6970 "for (var p in obj)"
6971 " if (p == 'prop') return false;"
6972 "return true;})()");
6973 CHECK(result->IsTrue());
6974 }
6975 env2.Dispose();
6976}
6977
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006978
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006979TEST(ContextDetachGlobal) {
6980 v8::HandleScope handle_scope;
6981 LocalContext env1;
6982 v8::Persistent<Context> env2 = Context::New();
6983
6984 Local<v8::Object> global1 = env1->Global();
6985
6986 Local<Value> foo = v8_str("foo");
6987
6988 // Set to the same domain.
6989 env1->SetSecurityToken(foo);
6990 env2->SetSecurityToken(foo);
6991
6992 // Enter env2
6993 env2->Enter();
6994
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006995 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006996 Local<v8::Object> global2 = env2->Global();
6997 global2->Set(v8_str("prop"), v8::Integer::New(1));
6998 CompileRun("function getProp() {return prop;}");
6999
7000 env1->Global()->Set(v8_str("getProp"),
7001 global2->Get(v8_str("getProp")));
7002
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007003 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007004 env2->Exit();
7005 env2->DetachGlobal();
7006 // env2 has a new global object.
7007 CHECK(!env2->Global()->Equals(global2));
7008
7009 v8::Persistent<Context> env3 =
7010 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
7011 env3->SetSecurityToken(v8_str("bar"));
7012 env3->Enter();
7013
7014 Local<v8::Object> global3 = env3->Global();
7015 CHECK_EQ(global2, global3);
7016 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
7017 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
7018 global3->Set(v8_str("prop"), v8::Integer::New(-1));
7019 global3->Set(v8_str("prop2"), v8::Integer::New(2));
7020 env3->Exit();
7021
7022 // Call getProp in env1, and it should return the value 1
7023 {
7024 Local<Value> get_prop = global1->Get(v8_str("getProp"));
7025 CHECK(get_prop->IsFunction());
7026 v8::TryCatch try_catch;
7027 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
7028 CHECK(!try_catch.HasCaught());
7029 CHECK_EQ(1, r->Int32Value());
7030 }
7031
7032 // Check that env3 is not accessible from env1
7033 {
7034 Local<Value> r = global3->Get(v8_str("prop2"));
7035 CHECK(r->IsUndefined());
7036 }
7037
7038 env2.Dispose();
7039 env3.Dispose();
7040}
7041
7042
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007043TEST(DetachAndReattachGlobal) {
7044 v8::HandleScope scope;
7045 LocalContext env1;
7046
7047 // Create second environment.
7048 v8::Persistent<Context> env2 = Context::New();
7049
7050 Local<Value> foo = v8_str("foo");
7051
7052 // Set same security token for env1 and env2.
7053 env1->SetSecurityToken(foo);
7054 env2->SetSecurityToken(foo);
7055
7056 // Create a property on the global object in env2.
7057 {
7058 v8::Context::Scope scope(env2);
7059 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
7060 }
7061
7062 // Create a reference to env2 global from env1 global.
7063 env1->Global()->Set(v8_str("other"), env2->Global());
7064
7065 // Check that we have access to other.p in env2 from env1.
7066 Local<Value> result = CompileRun("other.p");
7067 CHECK(result->IsInt32());
7068 CHECK_EQ(42, result->Int32Value());
7069
7070 // Hold on to global from env2 and detach global from env2.
7071 Local<v8::Object> global2 = env2->Global();
7072 env2->DetachGlobal();
7073
7074 // Check that the global has been detached. No other.p property can
7075 // be found.
7076 result = CompileRun("other.p");
7077 CHECK(result->IsUndefined());
7078
7079 // Reuse global2 for env3.
7080 v8::Persistent<Context> env3 =
7081 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
7082 CHECK_EQ(global2, env3->Global());
7083
7084 // Start by using the same security token for env3 as for env1 and env2.
7085 env3->SetSecurityToken(foo);
7086
7087 // Create a property on the global object in env3.
7088 {
7089 v8::Context::Scope scope(env3);
7090 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
7091 }
7092
7093 // Check that other.p is now the property in env3 and that we have access.
7094 result = CompileRun("other.p");
7095 CHECK(result->IsInt32());
7096 CHECK_EQ(24, result->Int32Value());
7097
7098 // Change security token for env3 to something different from env1 and env2.
7099 env3->SetSecurityToken(v8_str("bar"));
7100
7101 // Check that we do not have access to other.p in env1. |other| is now
7102 // the global object for env3 which has a different security token,
7103 // so access should be blocked.
7104 result = CompileRun("other.p");
7105 CHECK(result->IsUndefined());
7106
7107 // Detach the global for env3 and reattach it to env2.
7108 env3->DetachGlobal();
7109 env2->ReattachGlobal(global2);
7110
7111 // Check that we have access to other.p again in env1. |other| is now
7112 // the global object for env2 which has the same security token as env1.
7113 result = CompileRun("other.p");
7114 CHECK(result->IsInt32());
7115 CHECK_EQ(42, result->Int32Value());
7116
7117 env2.Dispose();
7118 env3.Dispose();
7119}
7120
7121
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007122static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007123static bool NamedAccessBlocker(Local<v8::Object> global,
7124 Local<Value> name,
7125 v8::AccessType type,
7126 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007127 return Context::GetCurrent()->Global()->Equals(global) ||
7128 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007129}
7130
7131
7132static bool IndexedAccessBlocker(Local<v8::Object> global,
7133 uint32_t key,
7134 v8::AccessType type,
7135 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007136 return Context::GetCurrent()->Global()->Equals(global) ||
7137 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007138}
7139
7140
7141static int g_echo_value = -1;
7142static v8::Handle<Value> EchoGetter(Local<String> name,
7143 const AccessorInfo& info) {
7144 return v8_num(g_echo_value);
7145}
7146
7147
7148static void EchoSetter(Local<String> name,
7149 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007150 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007151 if (value->IsNumber())
7152 g_echo_value = value->Int32Value();
7153}
7154
7155
7156static v8::Handle<Value> UnreachableGetter(Local<String> name,
7157 const AccessorInfo& info) {
7158 CHECK(false); // This function should not be called..
7159 return v8::Undefined();
7160}
7161
7162
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007163static void UnreachableSetter(Local<String>, Local<Value>,
7164 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007165 CHECK(false); // This function should nto be called.
7166}
7167
7168
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007169TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007170 v8::HandleScope handle_scope;
7171 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7172
7173 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7174 IndexedAccessBlocker);
7175
7176 // Add an accessor accessible by cross-domain JS code.
7177 global_template->SetAccessor(
7178 v8_str("accessible_prop"),
7179 EchoGetter, EchoSetter,
7180 v8::Handle<Value>(),
7181 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7182
7183 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00007184 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007185 UnreachableGetter, UnreachableSetter,
7186 v8::Handle<Value>(),
7187 v8::DEFAULT);
7188
7189 // Create an environment
7190 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7191 context0->Enter();
7192
7193 v8::Handle<v8::Object> global0 = context0->Global();
7194
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007195 // Define a property with JS getter and setter.
7196 CompileRun(
7197 "function getter() { return 'getter'; };\n"
7198 "function setter() { return 'setter'; }\n"
7199 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
7200
7201 Local<Value> getter = global0->Get(v8_str("getter"));
7202 Local<Value> setter = global0->Get(v8_str("setter"));
7203
7204 // And define normal element.
7205 global0->Set(239, v8_str("239"));
7206
7207 // Define an element with JS getter and setter.
7208 CompileRun(
7209 "function el_getter() { return 'el_getter'; };\n"
7210 "function el_setter() { return 'el_setter'; };\n"
7211 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
7212
7213 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
7214 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
7215
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007216 v8::HandleScope scope1;
7217
7218 v8::Persistent<Context> context1 = Context::New();
7219 context1->Enter();
7220
7221 v8::Handle<v8::Object> global1 = context1->Global();
7222 global1->Set(v8_str("other"), global0);
7223
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007224 // Access blocked property.
7225 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007226
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007227 ExpectUndefined("other.blocked_prop");
7228 ExpectUndefined(
7229 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7230 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007231
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007232 // Enable ACCESS_HAS
7233 allowed_access_type[v8::ACCESS_HAS] = true;
7234 ExpectUndefined("other.blocked_prop");
7235 // ... and now we can get the descriptor...
7236 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007237 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007238 // ... and enumerate the property.
7239 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
7240 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007241
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007242 // Access blocked element.
7243 CompileRun("other[239] = 1");
7244
7245 ExpectUndefined("other[239]");
7246 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
7247 ExpectFalse("propertyIsEnumerable.call(other, '239')");
7248
7249 // Enable ACCESS_HAS
7250 allowed_access_type[v8::ACCESS_HAS] = true;
7251 ExpectUndefined("other[239]");
7252 // ... and now we can get the descriptor...
7253 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
7254 // ... and enumerate the property.
7255 ExpectTrue("propertyIsEnumerable.call(other, '239')");
7256 allowed_access_type[v8::ACCESS_HAS] = false;
7257
7258 // Access a property with JS accessor.
7259 CompileRun("other.js_accessor_p = 2");
7260
7261 ExpectUndefined("other.js_accessor_p");
7262 ExpectUndefined(
7263 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7264
7265 // Enable ACCESS_HAS.
7266 allowed_access_type[v8::ACCESS_HAS] = true;
7267 ExpectUndefined("other.js_accessor_p");
7268 ExpectUndefined(
7269 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7270 ExpectUndefined(
7271 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7272 ExpectUndefined(
7273 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7274 allowed_access_type[v8::ACCESS_HAS] = false;
7275
7276 // Enable both ACCESS_HAS and ACCESS_GET.
7277 allowed_access_type[v8::ACCESS_HAS] = true;
7278 allowed_access_type[v8::ACCESS_GET] = true;
7279
7280 ExpectString("other.js_accessor_p", "getter");
7281 ExpectObject(
7282 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7283 ExpectUndefined(
7284 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7285 ExpectUndefined(
7286 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7287
7288 allowed_access_type[v8::ACCESS_GET] = false;
7289 allowed_access_type[v8::ACCESS_HAS] = false;
7290
7291 // Enable both ACCESS_HAS and ACCESS_SET.
7292 allowed_access_type[v8::ACCESS_HAS] = true;
7293 allowed_access_type[v8::ACCESS_SET] = true;
7294
7295 ExpectUndefined("other.js_accessor_p");
7296 ExpectUndefined(
7297 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7298 ExpectObject(
7299 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7300 ExpectUndefined(
7301 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7302
7303 allowed_access_type[v8::ACCESS_SET] = false;
7304 allowed_access_type[v8::ACCESS_HAS] = false;
7305
7306 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7307 allowed_access_type[v8::ACCESS_HAS] = true;
7308 allowed_access_type[v8::ACCESS_GET] = true;
7309 allowed_access_type[v8::ACCESS_SET] = true;
7310
7311 ExpectString("other.js_accessor_p", "getter");
7312 ExpectObject(
7313 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7314 ExpectObject(
7315 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7316 ExpectUndefined(
7317 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7318
7319 allowed_access_type[v8::ACCESS_SET] = false;
7320 allowed_access_type[v8::ACCESS_GET] = false;
7321 allowed_access_type[v8::ACCESS_HAS] = false;
7322
7323 // Access an element with JS accessor.
7324 CompileRun("other[42] = 2");
7325
7326 ExpectUndefined("other[42]");
7327 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7328
7329 // Enable ACCESS_HAS.
7330 allowed_access_type[v8::ACCESS_HAS] = true;
7331 ExpectUndefined("other[42]");
7332 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7333 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7334 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7335 allowed_access_type[v8::ACCESS_HAS] = false;
7336
7337 // Enable both ACCESS_HAS and ACCESS_GET.
7338 allowed_access_type[v8::ACCESS_HAS] = true;
7339 allowed_access_type[v8::ACCESS_GET] = true;
7340
7341 ExpectString("other[42]", "el_getter");
7342 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7343 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7344 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7345
7346 allowed_access_type[v8::ACCESS_GET] = false;
7347 allowed_access_type[v8::ACCESS_HAS] = false;
7348
7349 // Enable both ACCESS_HAS and ACCESS_SET.
7350 allowed_access_type[v8::ACCESS_HAS] = true;
7351 allowed_access_type[v8::ACCESS_SET] = true;
7352
7353 ExpectUndefined("other[42]");
7354 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7355 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7356 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7357
7358 allowed_access_type[v8::ACCESS_SET] = false;
7359 allowed_access_type[v8::ACCESS_HAS] = false;
7360
7361 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7362 allowed_access_type[v8::ACCESS_HAS] = true;
7363 allowed_access_type[v8::ACCESS_GET] = true;
7364 allowed_access_type[v8::ACCESS_SET] = true;
7365
7366 ExpectString("other[42]", "el_getter");
7367 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7368 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7369 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7370
7371 allowed_access_type[v8::ACCESS_SET] = false;
7372 allowed_access_type[v8::ACCESS_GET] = false;
7373 allowed_access_type[v8::ACCESS_HAS] = false;
7374
7375 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00007376
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007377 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007378 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007379 CHECK(value->IsNumber());
7380 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007381 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007382
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007383 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007384 CHECK(value->IsNumber());
7385 CHECK_EQ(3, value->Int32Value());
7386
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007387 value = CompileRun(
7388 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7389 CHECK(value->IsNumber());
7390 CHECK_EQ(3, value->Int32Value());
7391
7392 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00007393 CHECK(value->IsTrue());
7394
7395 // Enumeration doesn't enumerate accessors from inaccessible objects in
7396 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007397 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00007398 CompileRun("(function(){var obj = {'__proto__':other};"
7399 "for (var p in obj)"
7400 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7401 " return false;"
7402 " }"
7403 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007404 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00007405
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007406 context1->Exit();
7407 context0->Exit();
7408 context1.Dispose();
7409 context0.Dispose();
7410}
7411
7412
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007413TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00007414 v8::HandleScope handle_scope;
7415 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7416
7417 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7418 IndexedAccessBlocker);
7419
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007420 // Add accessible accessor.
7421 global_template->SetAccessor(
7422 v8_str("accessible_prop"),
7423 EchoGetter, EchoSetter,
7424 v8::Handle<Value>(),
7425 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7426
7427
ricow@chromium.org65001782011-02-15 13:36:41 +00007428 // Add an accessor that is not accessible by cross-domain JS code.
7429 global_template->SetAccessor(v8_str("blocked_prop"),
7430 UnreachableGetter, UnreachableSetter,
7431 v8::Handle<Value>(),
7432 v8::DEFAULT);
7433
7434 // Create an environment
7435 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7436 context0->Enter();
7437
7438 v8::Handle<v8::Object> global0 = context0->Global();
7439
7440 v8::Persistent<Context> context1 = Context::New();
7441 context1->Enter();
7442 v8::Handle<v8::Object> global1 = context1->Global();
7443 global1->Set(v8_str("other"), global0);
7444
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007445 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00007446 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007447
7448 ExpectUndefined("other.blocked_prop");
7449
7450 // Regression test for issue 1027.
7451 CompileRun("Object.defineProperty(\n"
7452 " other, 'blocked_prop', {configurable: false})");
7453 ExpectUndefined("other.blocked_prop");
7454 ExpectUndefined(
7455 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7456
7457 // Regression test for issue 1171.
7458 ExpectTrue("Object.isExtensible(other)");
7459 CompileRun("Object.preventExtensions(other)");
7460 ExpectTrue("Object.isExtensible(other)");
7461
7462 // Object.seal and Object.freeze.
7463 CompileRun("Object.freeze(other)");
7464 ExpectTrue("Object.isExtensible(other)");
7465
7466 CompileRun("Object.seal(other)");
7467 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007468
7469 // Regression test for issue 1250.
7470 // Make sure that we can set the accessible accessors value using normal
7471 // assignment.
7472 CompileRun("other.accessible_prop = 42");
7473 CHECK_EQ(42, g_echo_value);
7474
7475 v8::Handle<Value> value;
7476 // We follow Safari in ignoring assignments to host object accessors.
7477 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7478 value = CompileRun("other.accessible_prop == 42");
7479 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00007480}
7481
7482
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007483static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7484 Local<Value> name,
7485 v8::AccessType type,
7486 Local<Value> data) {
7487 return false;
7488}
7489
7490
7491static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7492 uint32_t key,
7493 v8::AccessType type,
7494 Local<Value> data) {
7495 return false;
7496}
7497
7498
7499THREADED_TEST(AccessControlGetOwnPropertyNames) {
7500 v8::HandleScope handle_scope;
7501 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7502
7503 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7504 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7505 GetOwnPropertyNamesIndexedBlocker);
7506
7507 // Create an environment
7508 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7509 context0->Enter();
7510
7511 v8::Handle<v8::Object> global0 = context0->Global();
7512
7513 v8::HandleScope scope1;
7514
7515 v8::Persistent<Context> context1 = Context::New();
7516 context1->Enter();
7517
7518 v8::Handle<v8::Object> global1 = context1->Global();
7519 global1->Set(v8_str("other"), global0);
7520 global1->Set(v8_str("object"), obj_template->NewInstance());
7521
7522 v8::Handle<Value> value;
7523
7524 // Attempt to get the property names of the other global object and
7525 // of an object that requires access checks. Accessing the other
7526 // global object should be blocked by access checks on the global
7527 // proxy object. Accessing the object that requires access checks
7528 // is blocked by the access checks on the object itself.
7529 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7530 CHECK(value->IsTrue());
7531
7532 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7533 CHECK(value->IsTrue());
7534
7535 context1->Exit();
7536 context0->Exit();
7537 context1.Dispose();
7538 context0.Dispose();
7539}
7540
7541
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007542static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7543 v8::Handle<v8::Array> result = v8::Array::New(1);
7544 result->Set(0, v8_str("x"));
7545 return result;
7546}
7547
7548
7549THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7550 v8::HandleScope handle_scope;
7551 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7552
7553 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7554 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7555 NamedPropertyEnumerator);
7556
7557 LocalContext context;
7558 v8::Handle<v8::Object> global = context->Global();
7559 global->Set(v8_str("object"), obj_template->NewInstance());
7560
7561 v8::Handle<Value> value =
7562 CompileRun("Object.getOwnPropertyNames(object).join(',')");
7563 CHECK_EQ(v8_str("x"), value);
7564}
7565
7566
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007567static v8::Handle<Value> ConstTenGetter(Local<String> name,
7568 const AccessorInfo& info) {
7569 return v8_num(10);
7570}
7571
7572
7573THREADED_TEST(CrossDomainAccessors) {
7574 v8::HandleScope handle_scope;
7575
7576 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7577
7578 v8::Handle<v8::ObjectTemplate> global_template =
7579 func_template->InstanceTemplate();
7580
7581 v8::Handle<v8::ObjectTemplate> proto_template =
7582 func_template->PrototypeTemplate();
7583
7584 // Add an accessor to proto that's accessible by cross-domain JS code.
7585 proto_template->SetAccessor(v8_str("accessible"),
7586 ConstTenGetter, 0,
7587 v8::Handle<Value>(),
7588 v8::ALL_CAN_READ);
7589
7590 // Add an accessor that is not accessible by cross-domain JS code.
7591 global_template->SetAccessor(v8_str("unreachable"),
7592 UnreachableGetter, 0,
7593 v8::Handle<Value>(),
7594 v8::DEFAULT);
7595
7596 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7597 context0->Enter();
7598
7599 Local<v8::Object> global = context0->Global();
7600 // Add a normal property that shadows 'accessible'
7601 global->Set(v8_str("accessible"), v8_num(11));
7602
7603 // Enter a new context.
7604 v8::HandleScope scope1;
7605 v8::Persistent<Context> context1 = Context::New();
7606 context1->Enter();
7607
7608 v8::Handle<v8::Object> global1 = context1->Global();
7609 global1->Set(v8_str("other"), global);
7610
7611 // Should return 10, instead of 11
7612 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7613 CHECK(value->IsNumber());
7614 CHECK_EQ(10, value->Int32Value());
7615
7616 value = v8_compile("other.unreachable")->Run();
7617 CHECK(value->IsUndefined());
7618
7619 context1->Exit();
7620 context0->Exit();
7621 context1.Dispose();
7622 context0.Dispose();
7623}
7624
7625
7626static int named_access_count = 0;
7627static int indexed_access_count = 0;
7628
7629static bool NamedAccessCounter(Local<v8::Object> global,
7630 Local<Value> name,
7631 v8::AccessType type,
7632 Local<Value> data) {
7633 named_access_count++;
7634 return true;
7635}
7636
7637
7638static bool IndexedAccessCounter(Local<v8::Object> global,
7639 uint32_t key,
7640 v8::AccessType type,
7641 Local<Value> data) {
7642 indexed_access_count++;
7643 return true;
7644}
7645
7646
7647// This one is too easily disturbed by other tests.
7648TEST(AccessControlIC) {
7649 named_access_count = 0;
7650 indexed_access_count = 0;
7651
7652 v8::HandleScope handle_scope;
7653
7654 // Create an environment.
7655 v8::Persistent<Context> context0 = Context::New();
7656 context0->Enter();
7657
7658 // Create an object that requires access-check functions to be
7659 // called for cross-domain access.
7660 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7661 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7662 IndexedAccessCounter);
7663 Local<v8::Object> object = object_template->NewInstance();
7664
7665 v8::HandleScope scope1;
7666
7667 // Create another environment.
7668 v8::Persistent<Context> context1 = Context::New();
7669 context1->Enter();
7670
7671 // Make easy access to the object from the other environment.
7672 v8::Handle<v8::Object> global1 = context1->Global();
7673 global1->Set(v8_str("obj"), object);
7674
7675 v8::Handle<Value> value;
7676
7677 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007678 CompileRun("function testProp(obj) {"
7679 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7680 " for (var j = 0; j < 10; j++) obj.prop;"
7681 " return obj.prop"
7682 "}");
7683 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007684 CHECK(value->IsNumber());
7685 CHECK_EQ(1, value->Int32Value());
7686 CHECK_EQ(21, named_access_count);
7687
7688 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007689 CompileRun("var p = 'prop';"
7690 "function testKeyed(obj) {"
7691 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7692 " for (var j = 0; j < 10; j++) obj[p];"
7693 " return obj[p];"
7694 "}");
7695 // Use obj which requires access checks. No inline caching is used
7696 // in that case.
7697 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007698 CHECK(value->IsNumber());
7699 CHECK_EQ(1, value->Int32Value());
7700 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007701 // Force the inline caches into generic state and try again.
7702 CompileRun("testKeyed({ a: 0 })");
7703 CompileRun("testKeyed({ b: 0 })");
7704 value = CompileRun("testKeyed(obj)");
7705 CHECK(value->IsNumber());
7706 CHECK_EQ(1, value->Int32Value());
7707 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007708
7709 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007710 CompileRun("function testIndexed(obj) {"
7711 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7712 " for (var j = 0; j < 10; j++) obj[0];"
7713 " return obj[0]"
7714 "}");
7715 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007716 CHECK(value->IsNumber());
7717 CHECK_EQ(1, value->Int32Value());
7718 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007719 // Force the inline caches into generic state.
7720 CompileRun("testIndexed(new Array(1))");
7721 // Test that the indexed access check is called.
7722 value = CompileRun("testIndexed(obj)");
7723 CHECK(value->IsNumber());
7724 CHECK_EQ(1, value->Int32Value());
7725 CHECK_EQ(42, indexed_access_count);
7726
7727 // Check that the named access check is called when invoking
7728 // functions on an object that requires access checks.
7729 CompileRun("obj.f = function() {}");
7730 CompileRun("function testCallNormal(obj) {"
7731 " for (var i = 0; i < 10; i++) obj.f();"
7732 "}");
7733 CompileRun("testCallNormal(obj)");
7734 CHECK_EQ(74, named_access_count);
7735
7736 // Force obj into slow case.
7737 value = CompileRun("delete obj.prop");
7738 CHECK(value->BooleanValue());
7739 // Force inline caches into dictionary probing mode.
7740 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7741 // Test that the named access check is called.
7742 value = CompileRun("testProp(obj);");
7743 CHECK(value->IsNumber());
7744 CHECK_EQ(1, value->Int32Value());
7745 CHECK_EQ(96, named_access_count);
7746
7747 // Force the call inline cache into dictionary probing mode.
7748 CompileRun("o.f = function() {}; testCallNormal(o)");
7749 // Test that the named access check is still called for each
7750 // invocation of the function.
7751 value = CompileRun("testCallNormal(obj)");
7752 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007753
7754 context1->Exit();
7755 context0->Exit();
7756 context1.Dispose();
7757 context0.Dispose();
7758}
7759
7760
7761static bool NamedAccessFlatten(Local<v8::Object> global,
7762 Local<Value> name,
7763 v8::AccessType type,
7764 Local<Value> data) {
7765 char buf[100];
7766 int len;
7767
7768 CHECK(name->IsString());
7769
7770 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007771 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007772 CHECK_EQ(4, len);
7773
7774 uint16_t buf2[100];
7775
7776 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007777 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007778 CHECK_EQ(4, len);
7779
7780 return true;
7781}
7782
7783
7784static bool IndexedAccessFlatten(Local<v8::Object> global,
7785 uint32_t key,
7786 v8::AccessType type,
7787 Local<Value> data) {
7788 return true;
7789}
7790
7791
7792// Regression test. In access checks, operations that may cause
7793// garbage collection are not allowed. It used to be the case that
7794// using the Write operation on a string could cause a garbage
7795// collection due to flattening of the string. This is no longer the
7796// case.
7797THREADED_TEST(AccessControlFlatten) {
7798 named_access_count = 0;
7799 indexed_access_count = 0;
7800
7801 v8::HandleScope handle_scope;
7802
7803 // Create an environment.
7804 v8::Persistent<Context> context0 = Context::New();
7805 context0->Enter();
7806
7807 // Create an object that requires access-check functions to be
7808 // called for cross-domain access.
7809 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7810 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7811 IndexedAccessFlatten);
7812 Local<v8::Object> object = object_template->NewInstance();
7813
7814 v8::HandleScope scope1;
7815
7816 // Create another environment.
7817 v8::Persistent<Context> context1 = Context::New();
7818 context1->Enter();
7819
7820 // Make easy access to the object from the other environment.
7821 v8::Handle<v8::Object> global1 = context1->Global();
7822 global1->Set(v8_str("obj"), object);
7823
7824 v8::Handle<Value> value;
7825
7826 value = v8_compile("var p = 'as' + 'df';")->Run();
7827 value = v8_compile("obj[p];")->Run();
7828
7829 context1->Exit();
7830 context0->Exit();
7831 context1.Dispose();
7832 context0.Dispose();
7833}
7834
7835
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007836static v8::Handle<Value> AccessControlNamedGetter(
7837 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007838 return v8::Integer::New(42);
7839}
7840
7841
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007842static v8::Handle<Value> AccessControlNamedSetter(
7843 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007844 return value;
7845}
7846
7847
7848static v8::Handle<Value> AccessControlIndexedGetter(
7849 uint32_t index,
7850 const AccessorInfo& info) {
7851 return v8_num(42);
7852}
7853
7854
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007855static v8::Handle<Value> AccessControlIndexedSetter(
7856 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007857 return value;
7858}
7859
7860
7861THREADED_TEST(AccessControlInterceptorIC) {
7862 named_access_count = 0;
7863 indexed_access_count = 0;
7864
7865 v8::HandleScope handle_scope;
7866
7867 // Create an environment.
7868 v8::Persistent<Context> context0 = Context::New();
7869 context0->Enter();
7870
7871 // Create an object that requires access-check functions to be
7872 // called for cross-domain access. The object also has interceptors
7873 // interceptor.
7874 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7875 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7876 IndexedAccessCounter);
7877 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7878 AccessControlNamedSetter);
7879 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7880 AccessControlIndexedSetter);
7881 Local<v8::Object> object = object_template->NewInstance();
7882
7883 v8::HandleScope scope1;
7884
7885 // Create another environment.
7886 v8::Persistent<Context> context1 = Context::New();
7887 context1->Enter();
7888
7889 // Make easy access to the object from the other environment.
7890 v8::Handle<v8::Object> global1 = context1->Global();
7891 global1->Set(v8_str("obj"), object);
7892
7893 v8::Handle<Value> value;
7894
7895 // Check that the named access-control function is called every time
7896 // eventhough there is an interceptor on the object.
7897 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7898 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7899 "obj.x")->Run();
7900 CHECK(value->IsNumber());
7901 CHECK_EQ(42, value->Int32Value());
7902 CHECK_EQ(21, named_access_count);
7903
7904 value = v8_compile("var p = 'x';")->Run();
7905 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7906 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7907 "obj[p]")->Run();
7908 CHECK(value->IsNumber());
7909 CHECK_EQ(42, value->Int32Value());
7910 CHECK_EQ(42, named_access_count);
7911
7912 // Check that the indexed access-control function is called every
7913 // time eventhough there is an interceptor on the object.
7914 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7915 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7916 "obj[0]")->Run();
7917 CHECK(value->IsNumber());
7918 CHECK_EQ(42, value->Int32Value());
7919 CHECK_EQ(21, indexed_access_count);
7920
7921 context1->Exit();
7922 context0->Exit();
7923 context1.Dispose();
7924 context0.Dispose();
7925}
7926
7927
7928THREADED_TEST(Version) {
7929 v8::V8::GetVersion();
7930}
7931
7932
7933static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7934 ApiTestFuzzer::Fuzz();
7935 return v8_num(12);
7936}
7937
7938
7939THREADED_TEST(InstanceProperties) {
7940 v8::HandleScope handle_scope;
7941 LocalContext context;
7942
7943 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7944 Local<ObjectTemplate> instance = t->InstanceTemplate();
7945
7946 instance->Set(v8_str("x"), v8_num(42));
7947 instance->Set(v8_str("f"),
7948 v8::FunctionTemplate::New(InstanceFunctionCallback));
7949
7950 Local<Value> o = t->GetFunction()->NewInstance();
7951
7952 context->Global()->Set(v8_str("i"), o);
7953 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7954 CHECK_EQ(42, value->Int32Value());
7955
7956 value = Script::Compile(v8_str("i.f()"))->Run();
7957 CHECK_EQ(12, value->Int32Value());
7958}
7959
7960
7961static v8::Handle<Value>
7962GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7963 ApiTestFuzzer::Fuzz();
7964 return v8::Handle<Value>();
7965}
7966
7967
7968THREADED_TEST(GlobalObjectInstanceProperties) {
7969 v8::HandleScope handle_scope;
7970
7971 Local<Value> global_object;
7972
7973 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7974 t->InstanceTemplate()->SetNamedPropertyHandler(
7975 GlobalObjectInstancePropertiesGet);
7976 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7977 instance_template->Set(v8_str("x"), v8_num(42));
7978 instance_template->Set(v8_str("f"),
7979 v8::FunctionTemplate::New(InstanceFunctionCallback));
7980
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007981 // The script to check how Crankshaft compiles missing global function
7982 // invocations. function g is not defined and should throw on call.
7983 const char* script =
7984 "function wrapper(call) {"
7985 " var x = 0, y = 1;"
7986 " for (var i = 0; i < 1000; i++) {"
7987 " x += i * 100;"
7988 " y += i * 100;"
7989 " }"
7990 " if (call) g();"
7991 "}"
7992 "for (var i = 0; i < 17; i++) wrapper(false);"
7993 "var thrown = 0;"
7994 "try { wrapper(true); } catch (e) { thrown = 1; };"
7995 "thrown";
7996
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007997 {
7998 LocalContext env(NULL, instance_template);
7999 // Hold on to the global object so it can be used again in another
8000 // environment initialization.
8001 global_object = env->Global();
8002
8003 Local<Value> value = Script::Compile(v8_str("x"))->Run();
8004 CHECK_EQ(42, value->Int32Value());
8005 value = Script::Compile(v8_str("f()"))->Run();
8006 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008007 value = Script::Compile(v8_str(script))->Run();
8008 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008009 }
8010
8011 {
8012 // Create new environment reusing the global object.
8013 LocalContext env(NULL, instance_template, global_object);
8014 Local<Value> value = Script::Compile(v8_str("x"))->Run();
8015 CHECK_EQ(42, value->Int32Value());
8016 value = Script::Compile(v8_str("f()"))->Run();
8017 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008018 value = Script::Compile(v8_str(script))->Run();
8019 CHECK_EQ(1, value->Int32Value());
8020 }
8021}
8022
8023
8024THREADED_TEST(CallKnownGlobalReceiver) {
8025 v8::HandleScope handle_scope;
8026
8027 Local<Value> global_object;
8028
8029 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8030 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8031
8032 // The script to check that we leave global object not
8033 // global object proxy on stack when we deoptimize from inside
8034 // arguments evaluation.
8035 // To provoke error we need to both force deoptimization
8036 // from arguments evaluation and to force CallIC to take
8037 // CallIC_Miss code path that can't cope with global proxy.
8038 const char* script =
8039 "function bar(x, y) { try { } finally { } }"
8040 "function baz(x) { try { } finally { } }"
8041 "function bom(x) { try { } finally { } }"
8042 "function foo(x) { bar([x], bom(2)); }"
8043 "for (var i = 0; i < 10000; i++) foo(1);"
8044 "foo";
8045
8046 Local<Value> foo;
8047 {
8048 LocalContext env(NULL, instance_template);
8049 // Hold on to the global object so it can be used again in another
8050 // environment initialization.
8051 global_object = env->Global();
8052 foo = Script::Compile(v8_str(script))->Run();
8053 }
8054
8055 {
8056 // Create new environment reusing the global object.
8057 LocalContext env(NULL, instance_template, global_object);
8058 env->Global()->Set(v8_str("foo"), foo);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008059 Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008060 }
8061}
8062
8063
8064static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
8065 ApiTestFuzzer::Fuzz();
8066 return v8_num(42);
8067}
8068
8069
8070static int shadow_y;
8071static int shadow_y_setter_call_count;
8072static int shadow_y_getter_call_count;
8073
8074
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008075static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008076 shadow_y_setter_call_count++;
8077 shadow_y = 42;
8078}
8079
8080
8081static v8::Handle<Value> ShadowYGetter(Local<String> name,
8082 const AccessorInfo& info) {
8083 ApiTestFuzzer::Fuzz();
8084 shadow_y_getter_call_count++;
8085 return v8_num(shadow_y);
8086}
8087
8088
8089static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
8090 const AccessorInfo& info) {
8091 return v8::Handle<Value>();
8092}
8093
8094
8095static v8::Handle<Value> ShadowNamedGet(Local<String> key,
8096 const AccessorInfo&) {
8097 return v8::Handle<Value>();
8098}
8099
8100
8101THREADED_TEST(ShadowObject) {
8102 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
8103 v8::HandleScope handle_scope;
8104
8105 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
8106 LocalContext context(NULL, global_template);
8107
8108 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8109 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
8110 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
8111 Local<ObjectTemplate> proto = t->PrototypeTemplate();
8112 Local<ObjectTemplate> instance = t->InstanceTemplate();
8113
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008114 proto->Set(v8_str("f"),
mmassi@chromium.org49a44672012-12-04 13:52:03 +00008115 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008116 proto->Set(v8_str("x"), v8_num(12));
8117
8118 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
8119
8120 Local<Value> o = t->GetFunction()->NewInstance();
8121 context->Global()->Set(v8_str("__proto__"), o);
8122
8123 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008124 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008125 CHECK(value->IsBoolean());
8126 CHECK(!value->BooleanValue());
8127
8128 value = Script::Compile(v8_str("x"))->Run();
8129 CHECK_EQ(12, value->Int32Value());
8130
8131 value = Script::Compile(v8_str("f()"))->Run();
8132 CHECK_EQ(42, value->Int32Value());
8133
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008134 Script::Compile(v8_str("y = 43"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008135 CHECK_EQ(1, shadow_y_setter_call_count);
8136 value = Script::Compile(v8_str("y"))->Run();
8137 CHECK_EQ(1, shadow_y_getter_call_count);
8138 CHECK_EQ(42, value->Int32Value());
8139}
8140
8141
8142THREADED_TEST(HiddenPrototype) {
8143 v8::HandleScope handle_scope;
8144 LocalContext context;
8145
8146 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8147 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8148 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8149 t1->SetHiddenPrototype(true);
8150 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8151 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8152 t2->SetHiddenPrototype(true);
8153 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8154 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8155 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8156
8157 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8158 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8159 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8160 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8161
8162 // Setting the prototype on an object skips hidden prototypes.
8163 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8164 o0->Set(v8_str("__proto__"), o1);
8165 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8166 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8167 o0->Set(v8_str("__proto__"), o2);
8168 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8169 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8170 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8171 o0->Set(v8_str("__proto__"), o3);
8172 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8173 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8174 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8175 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8176
8177 // Getting the prototype of o0 should get the first visible one
8178 // which is o3. Therefore, z should not be defined on the prototype
8179 // object.
8180 Local<Value> proto = o0->Get(v8_str("__proto__"));
8181 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008182 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008183}
8184
8185
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008186THREADED_TEST(HiddenPrototypeSet) {
8187 v8::HandleScope handle_scope;
8188 LocalContext context;
8189
8190 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
8191 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
8192 ht->SetHiddenPrototype(true);
8193 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
8194 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8195
8196 Local<v8::Object> o = ot->GetFunction()->NewInstance();
8197 Local<v8::Object> h = ht->GetFunction()->NewInstance();
8198 Local<v8::Object> p = pt->GetFunction()->NewInstance();
8199 o->Set(v8_str("__proto__"), h);
8200 h->Set(v8_str("__proto__"), p);
8201
8202 // Setting a property that exists on the hidden prototype goes there.
8203 o->Set(v8_str("x"), v8_num(7));
8204 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
8205 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
8206 CHECK(p->Get(v8_str("x"))->IsUndefined());
8207
8208 // Setting a new property should not be forwarded to the hidden prototype.
8209 o->Set(v8_str("y"), v8_num(6));
8210 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
8211 CHECK(h->Get(v8_str("y"))->IsUndefined());
8212 CHECK(p->Get(v8_str("y"))->IsUndefined());
8213
8214 // Setting a property that only exists on a prototype of the hidden prototype
8215 // is treated normally again.
8216 p->Set(v8_str("z"), v8_num(8));
8217 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
8218 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
8219 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
8220 o->Set(v8_str("z"), v8_num(9));
8221 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
8222 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
8223 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
8224}
8225
8226
8227// Regression test for issue 2457.
8228THREADED_TEST(HiddenPrototypeIdentityHash) {
8229 v8::HandleScope handle_scope;
8230 LocalContext context;
8231
8232 Handle<FunctionTemplate> t = FunctionTemplate::New();
8233 t->SetHiddenPrototype(true);
8234 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
8235 Handle<Object> p = t->GetFunction()->NewInstance();
8236 Handle<Object> o = Object::New();
8237 o->SetPrototype(p);
8238
8239 int hash = o->GetIdentityHash();
8240 USE(hash);
8241 o->Set(v8_str("foo"), v8_num(42));
8242 ASSERT_EQ(hash, o->GetIdentityHash());
8243}
8244
8245
ager@chromium.org5c838252010-02-19 08:53:10 +00008246THREADED_TEST(SetPrototype) {
8247 v8::HandleScope handle_scope;
8248 LocalContext context;
8249
8250 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8251 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8252 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8253 t1->SetHiddenPrototype(true);
8254 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8255 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8256 t2->SetHiddenPrototype(true);
8257 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8258 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8259 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8260
8261 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8262 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8263 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8264 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8265
8266 // Setting the prototype on an object does not skip hidden prototypes.
8267 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8268 CHECK(o0->SetPrototype(o1));
8269 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8270 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8271 CHECK(o1->SetPrototype(o2));
8272 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8273 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8274 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8275 CHECK(o2->SetPrototype(o3));
8276 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8277 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8278 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8279 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8280
8281 // Getting the prototype of o0 should get the first visible one
8282 // which is o3. Therefore, z should not be defined on the prototype
8283 // object.
8284 Local<Value> proto = o0->Get(v8_str("__proto__"));
8285 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008286 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008287
8288 // However, Object::GetPrototype ignores hidden prototype.
8289 Local<Value> proto0 = o0->GetPrototype();
8290 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008291 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00008292
8293 Local<Value> proto1 = o1->GetPrototype();
8294 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008295 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00008296
8297 Local<Value> proto2 = o2->GetPrototype();
8298 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008299 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008300}
8301
8302
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008303// Getting property names of an object with a prototype chain that
8304// triggers dictionary elements in GetLocalPropertyNames() shouldn't
8305// crash the runtime.
8306THREADED_TEST(Regress91517) {
8307 i::FLAG_allow_natives_syntax = true;
8308 v8::HandleScope handle_scope;
8309 LocalContext context;
8310
8311 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8312 t1->SetHiddenPrototype(true);
8313 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
8314 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8315 t2->SetHiddenPrototype(true);
8316 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
8317 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
8318 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
8319 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8320 t3->SetHiddenPrototype(true);
8321 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8322 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8323 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8324
8325 // Force dictionary-based properties.
8326 i::ScopedVector<char> name_buf(1024);
8327 for (int i = 1; i <= 1000; i++) {
8328 i::OS::SNPrintF(name_buf, "sdf%d", i);
8329 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8330 }
8331
8332 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8333 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8334 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8335 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8336
8337 // Create prototype chain of hidden prototypes.
8338 CHECK(o4->SetPrototype(o3));
8339 CHECK(o3->SetPrototype(o2));
8340 CHECK(o2->SetPrototype(o1));
8341
8342 // Call the runtime version of GetLocalPropertyNames() on the natively
8343 // created object through JavaScript.
8344 context->Global()->Set(v8_str("obj"), o4);
8345 CompileRun("var names = %GetLocalPropertyNames(obj);");
8346
8347 ExpectInt32("names.length", 1006);
8348 ExpectTrue("names.indexOf(\"baz\") >= 0");
8349 ExpectTrue("names.indexOf(\"boo\") >= 0");
8350 ExpectTrue("names.indexOf(\"foo\") >= 0");
8351 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8352 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8353 ExpectFalse("names[1005] == undefined");
8354}
8355
8356
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008357THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00008358 v8::HandleScope handle_scope;
8359 LocalContext context;
8360
8361 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008362 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8363 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00008364 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008365 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008366 CHECK(CompileRun(
8367 "(function() {"
8368 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008369 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008370 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008371 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8372 CHECK_EQ(42,
8373 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008374
8375 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008376 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00008377 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008378 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008379 CHECK(CompileRun(
8380 "(function() {"
8381 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008382 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008383 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008384 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008385}
8386
8387
ager@chromium.org5c838252010-02-19 08:53:10 +00008388THREADED_TEST(SetPrototypeThrows) {
8389 v8::HandleScope handle_scope;
8390 LocalContext context;
8391
8392 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8393
8394 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8395 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8396
8397 CHECK(o0->SetPrototype(o1));
8398 // If setting the prototype leads to the cycle, SetPrototype should
8399 // return false and keep VM in sane state.
8400 v8::TryCatch try_catch;
8401 CHECK(!o1->SetPrototype(o0));
8402 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008403 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00008404
8405 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8406}
8407
8408
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008409THREADED_TEST(GetterSetterExceptions) {
8410 v8::HandleScope handle_scope;
8411 LocalContext context;
8412 CompileRun(
8413 "function Foo() { };"
8414 "function Throw() { throw 5; };"
8415 "var x = { };"
8416 "x.__defineSetter__('set', Throw);"
8417 "x.__defineGetter__('get', Throw);");
8418 Local<v8::Object> x =
8419 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8420 v8::TryCatch try_catch;
8421 x->Set(v8_str("set"), v8::Integer::New(8));
8422 x->Get(v8_str("get"));
8423 x->Set(v8_str("set"), v8::Integer::New(8));
8424 x->Get(v8_str("get"));
8425 x->Set(v8_str("set"), v8::Integer::New(8));
8426 x->Get(v8_str("get"));
8427 x->Set(v8_str("set"), v8::Integer::New(8));
8428 x->Get(v8_str("get"));
8429}
8430
8431
8432THREADED_TEST(Constructor) {
8433 v8::HandleScope handle_scope;
8434 LocalContext context;
8435 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8436 templ->SetClassName(v8_str("Fun"));
8437 Local<Function> cons = templ->GetFunction();
8438 context->Global()->Set(v8_str("Fun"), cons);
8439 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008440 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008441 CHECK(obj->IsJSObject());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008442 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8443 CHECK(value->BooleanValue());
8444}
8445
lrn@chromium.org1c092762011-05-09 09:42:16 +00008446
8447static Handle<Value> ConstructorCallback(const Arguments& args) {
8448 ApiTestFuzzer::Fuzz();
8449 Local<Object> This;
8450
8451 if (args.IsConstructCall()) {
8452 Local<Object> Holder = args.Holder();
8453 This = Object::New();
8454 Local<Value> proto = Holder->GetPrototype();
8455 if (proto->IsObject()) {
8456 This->SetPrototype(proto);
8457 }
8458 } else {
8459 This = args.This();
8460 }
8461
8462 This->Set(v8_str("a"), args[0]);
8463 return This;
8464}
8465
8466
8467static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8468 ApiTestFuzzer::Fuzz();
8469 return args[0];
8470}
8471
8472
8473THREADED_TEST(ConstructorForObject) {
8474 v8::HandleScope handle_scope;
8475 LocalContext context;
8476
8477 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8478 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8479 Local<Object> instance = instance_template->NewInstance();
8480 context->Global()->Set(v8_str("obj"), instance);
8481 v8::TryCatch try_catch;
8482 Local<Value> value;
8483 CHECK(!try_catch.HasCaught());
8484
8485 // Call the Object's constructor with a 32-bit signed integer.
8486 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8487 CHECK(!try_catch.HasCaught());
8488 CHECK(value->IsInt32());
8489 CHECK_EQ(28, value->Int32Value());
8490
8491 Local<Value> args1[] = { v8_num(28) };
8492 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8493 CHECK(value_obj1->IsObject());
8494 Local<Object> object1 = Local<Object>::Cast(value_obj1);
8495 value = object1->Get(v8_str("a"));
8496 CHECK(value->IsInt32());
8497 CHECK(!try_catch.HasCaught());
8498 CHECK_EQ(28, value->Int32Value());
8499
8500 // Call the Object's constructor with a String.
8501 value = CompileRun(
8502 "(function() { var o = new obj('tipli'); return o.a; })()");
8503 CHECK(!try_catch.HasCaught());
8504 CHECK(value->IsString());
8505 String::AsciiValue string_value1(value->ToString());
8506 CHECK_EQ("tipli", *string_value1);
8507
8508 Local<Value> args2[] = { v8_str("tipli") };
8509 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8510 CHECK(value_obj2->IsObject());
8511 Local<Object> object2 = Local<Object>::Cast(value_obj2);
8512 value = object2->Get(v8_str("a"));
8513 CHECK(!try_catch.HasCaught());
8514 CHECK(value->IsString());
8515 String::AsciiValue string_value2(value->ToString());
8516 CHECK_EQ("tipli", *string_value2);
8517
8518 // Call the Object's constructor with a Boolean.
8519 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8520 CHECK(!try_catch.HasCaught());
8521 CHECK(value->IsBoolean());
8522 CHECK_EQ(true, value->BooleanValue());
8523
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008524 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00008525 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8526 CHECK(value_obj3->IsObject());
8527 Local<Object> object3 = Local<Object>::Cast(value_obj3);
8528 value = object3->Get(v8_str("a"));
8529 CHECK(!try_catch.HasCaught());
8530 CHECK(value->IsBoolean());
8531 CHECK_EQ(true, value->BooleanValue());
8532
8533 // Call the Object's constructor with undefined.
8534 Handle<Value> args4[] = { v8::Undefined() };
8535 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8536 CHECK(value_obj4->IsObject());
8537 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8538 value = object4->Get(v8_str("a"));
8539 CHECK(!try_catch.HasCaught());
8540 CHECK(value->IsUndefined());
8541
8542 // Call the Object's constructor with null.
8543 Handle<Value> args5[] = { v8::Null() };
8544 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8545 CHECK(value_obj5->IsObject());
8546 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8547 value = object5->Get(v8_str("a"));
8548 CHECK(!try_catch.HasCaught());
8549 CHECK(value->IsNull());
8550 }
8551
8552 // Check exception handling when there is no constructor set for the Object.
8553 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8554 Local<Object> instance = instance_template->NewInstance();
8555 context->Global()->Set(v8_str("obj2"), instance);
8556 v8::TryCatch try_catch;
8557 Local<Value> value;
8558 CHECK(!try_catch.HasCaught());
8559
8560 value = CompileRun("new obj2(28)");
8561 CHECK(try_catch.HasCaught());
8562 String::AsciiValue exception_value1(try_catch.Exception());
8563 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8564 try_catch.Reset();
8565
8566 Local<Value> args[] = { v8_num(29) };
8567 value = instance->CallAsConstructor(1, args);
8568 CHECK(try_catch.HasCaught());
8569 String::AsciiValue exception_value2(try_catch.Exception());
8570 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8571 try_catch.Reset();
8572 }
8573
8574 // Check the case when constructor throws exception.
8575 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8576 instance_template->SetCallAsFunctionHandler(ThrowValue);
8577 Local<Object> instance = instance_template->NewInstance();
8578 context->Global()->Set(v8_str("obj3"), instance);
8579 v8::TryCatch try_catch;
8580 Local<Value> value;
8581 CHECK(!try_catch.HasCaught());
8582
8583 value = CompileRun("new obj3(22)");
8584 CHECK(try_catch.HasCaught());
8585 String::AsciiValue exception_value1(try_catch.Exception());
8586 CHECK_EQ("22", *exception_value1);
8587 try_catch.Reset();
8588
8589 Local<Value> args[] = { v8_num(23) };
8590 value = instance->CallAsConstructor(1, args);
8591 CHECK(try_catch.HasCaught());
8592 String::AsciiValue exception_value2(try_catch.Exception());
8593 CHECK_EQ("23", *exception_value2);
8594 try_catch.Reset();
8595 }
8596
8597 // Check whether constructor returns with an object or non-object.
8598 { Local<FunctionTemplate> function_template =
8599 FunctionTemplate::New(FakeConstructorCallback);
8600 Local<Function> function = function_template->GetFunction();
8601 Local<Object> instance1 = function;
8602 context->Global()->Set(v8_str("obj4"), instance1);
8603 v8::TryCatch try_catch;
8604 Local<Value> value;
8605 CHECK(!try_catch.HasCaught());
8606
8607 CHECK(instance1->IsObject());
8608 CHECK(instance1->IsFunction());
8609
8610 value = CompileRun("new obj4(28)");
8611 CHECK(!try_catch.HasCaught());
8612 CHECK(value->IsObject());
8613
8614 Local<Value> args1[] = { v8_num(28) };
8615 value = instance1->CallAsConstructor(1, args1);
8616 CHECK(!try_catch.HasCaught());
8617 CHECK(value->IsObject());
8618
8619 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8620 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8621 Local<Object> instance2 = instance_template->NewInstance();
8622 context->Global()->Set(v8_str("obj5"), instance2);
8623 CHECK(!try_catch.HasCaught());
8624
8625 CHECK(instance2->IsObject());
8626 CHECK(!instance2->IsFunction());
8627
8628 value = CompileRun("new obj5(28)");
8629 CHECK(!try_catch.HasCaught());
8630 CHECK(!value->IsObject());
8631
8632 Local<Value> args2[] = { v8_num(28) };
8633 value = instance2->CallAsConstructor(1, args2);
8634 CHECK(!try_catch.HasCaught());
8635 CHECK(!value->IsObject());
8636 }
8637}
8638
8639
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008640THREADED_TEST(FunctionDescriptorException) {
8641 v8::HandleScope handle_scope;
8642 LocalContext context;
8643 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8644 templ->SetClassName(v8_str("Fun"));
8645 Local<Function> cons = templ->GetFunction();
8646 context->Global()->Set(v8_str("Fun"), cons);
8647 Local<Value> value = CompileRun(
8648 "function test() {"
8649 " try {"
8650 " (new Fun()).blah()"
8651 " } catch (e) {"
8652 " var str = String(e);"
8653 " if (str.indexOf('TypeError') == -1) return 1;"
8654 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00008655 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008656 " return 0;"
8657 " }"
8658 " return 4;"
8659 "}"
8660 "test();");
8661 CHECK_EQ(0, value->Int32Value());
8662}
8663
8664
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008665THREADED_TEST(EvalAliasedDynamic) {
8666 v8::HandleScope scope;
8667 LocalContext current;
8668
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008669 // Tests where aliased eval can only be resolved dynamically.
8670 Local<Script> script =
8671 Script::Compile(v8_str("function f(x) { "
8672 " var foo = 2;"
8673 " with (x) { return eval('foo'); }"
8674 "}"
8675 "foo = 0;"
8676 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008677 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008678 "var x = new Object();"
8679 "x.eval = function(x) { return 1; };"
8680 "result3 = f(x);"));
8681 script->Run();
8682 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8683 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8684 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8685
8686 v8::TryCatch try_catch;
8687 script =
8688 Script::Compile(v8_str("function f(x) { "
8689 " var bar = 2;"
8690 " with (x) { return eval('bar'); }"
8691 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008692 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008693 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008694 CHECK(!try_catch.HasCaught());
8695 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8696
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008697 try_catch.Reset();
8698}
8699
8700
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008701THREADED_TEST(CrossEval) {
8702 v8::HandleScope scope;
8703 LocalContext other;
8704 LocalContext current;
8705
8706 Local<String> token = v8_str("<security token>");
8707 other->SetSecurityToken(token);
8708 current->SetSecurityToken(token);
8709
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008710 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008711 current->Global()->Set(v8_str("other"), other->Global());
8712
8713 // Check that new variables are introduced in other context.
8714 Local<Script> script =
8715 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8716 script->Run();
8717 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8718 CHECK_EQ(1234, foo->Int32Value());
8719 CHECK(!current->Global()->Has(v8_str("foo")));
8720
8721 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008722 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008723 script =
8724 Script::Compile(v8_str("other.eval('na = 1234')"));
8725 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008726 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8727 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008728
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008729 // Check that global variables in current context are not visible in other
8730 // context.
8731 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008732 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008733 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008734 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008735 CHECK(try_catch.HasCaught());
8736 try_catch.Reset();
8737
8738 // Check that local variables in current context are not visible in other
8739 // context.
8740 script =
8741 Script::Compile(v8_str("(function() { "
8742 " var baz = 87;"
8743 " return other.eval('baz');"
8744 "})();"));
8745 result = script->Run();
8746 CHECK(try_catch.HasCaught());
8747 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008748
8749 // Check that global variables in the other environment are visible
8750 // when evaluting code.
8751 other->Global()->Set(v8_str("bis"), v8_num(1234));
8752 script = Script::Compile(v8_str("other.eval('bis')"));
8753 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008754 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008755
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008756 // Check that the 'this' pointer points to the global object evaluating
8757 // code.
8758 other->Global()->Set(v8_str("t"), other->Global());
8759 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008760 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008761 CHECK(result->IsTrue());
8762 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008763
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008764 // Check that variables introduced in with-statement are not visible in
8765 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008766 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008767 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008768 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008769 CHECK(try_catch.HasCaught());
8770 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008771
8772 // Check that you cannot use 'eval.call' with another object than the
8773 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008774 script =
8775 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8776 result = script->Run();
8777 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008778}
8779
8780
ager@chromium.orge2902be2009-06-08 12:21:35 +00008781// Test that calling eval in a context which has been detached from
8782// its global throws an exception. This behavior is consistent with
8783// other JavaScript implementations.
8784THREADED_TEST(EvalInDetachedGlobal) {
8785 v8::HandleScope scope;
8786
8787 v8::Persistent<Context> context0 = Context::New();
8788 v8::Persistent<Context> context1 = Context::New();
8789
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008790 // Set up function in context0 that uses eval from context0.
ager@chromium.orge2902be2009-06-08 12:21:35 +00008791 context0->Enter();
8792 v8::Handle<v8::Value> fun =
8793 CompileRun("var x = 42;"
8794 "(function() {"
8795 " var e = eval;"
8796 " return function(s) { return e(s); }"
8797 "})()");
8798 context0->Exit();
8799
8800 // Put the function into context1 and call it before and after
8801 // detaching the global. Before detaching, the call succeeds and
8802 // after detaching and exception is thrown.
8803 context1->Enter();
8804 context1->Global()->Set(v8_str("fun"), fun);
8805 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8806 CHECK_EQ(42, x_value->Int32Value());
8807 context0->DetachGlobal();
8808 v8::TryCatch catcher;
8809 x_value = CompileRun("fun('x')");
8810 CHECK(x_value.IsEmpty());
8811 CHECK(catcher.HasCaught());
8812 context1->Exit();
8813
8814 context1.Dispose();
8815 context0.Dispose();
8816}
8817
8818
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008819THREADED_TEST(CrossLazyLoad) {
8820 v8::HandleScope scope;
8821 LocalContext other;
8822 LocalContext current;
8823
8824 Local<String> token = v8_str("<security token>");
8825 other->SetSecurityToken(token);
8826 current->SetSecurityToken(token);
8827
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008828 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008829 current->Global()->Set(v8_str("other"), other->Global());
8830
8831 // Trigger lazy loading in other context.
8832 Local<Script> script =
8833 Script::Compile(v8_str("other.eval('new Date(42)')"));
8834 Local<Value> value = script->Run();
8835 CHECK_EQ(42.0, value->NumberValue());
8836}
8837
8838
8839static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8840 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008841 if (args.IsConstructCall()) {
8842 if (args[0]->IsInt32()) {
8843 return v8_num(-args[0]->Int32Value());
8844 }
8845 }
8846
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008847 return args[0];
8848}
8849
8850
8851// Test that a call handler can be set for objects which will allow
8852// non-function objects created through the API to be called as
8853// functions.
8854THREADED_TEST(CallAsFunction) {
8855 v8::HandleScope scope;
8856 LocalContext context;
8857
lrn@chromium.org1c092762011-05-09 09:42:16 +00008858 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8859 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8860 instance_template->SetCallAsFunctionHandler(call_as_function);
8861 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8862 context->Global()->Set(v8_str("obj"), instance);
8863 v8::TryCatch try_catch;
8864 Local<Value> value;
8865 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008866
lrn@chromium.org1c092762011-05-09 09:42:16 +00008867 value = CompileRun("obj(42)");
8868 CHECK(!try_catch.HasCaught());
8869 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008870
lrn@chromium.org1c092762011-05-09 09:42:16 +00008871 value = CompileRun("(function(o){return o(49)})(obj)");
8872 CHECK(!try_catch.HasCaught());
8873 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008874
lrn@chromium.org1c092762011-05-09 09:42:16 +00008875 // test special case of call as function
8876 value = CompileRun("[obj]['0'](45)");
8877 CHECK(!try_catch.HasCaught());
8878 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008879
lrn@chromium.org1c092762011-05-09 09:42:16 +00008880 value = CompileRun("obj.call = Function.prototype.call;"
8881 "obj.call(null, 87)");
8882 CHECK(!try_catch.HasCaught());
8883 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008884
lrn@chromium.org1c092762011-05-09 09:42:16 +00008885 // Regression tests for bug #1116356: Calling call through call/apply
8886 // must work for non-function receivers.
8887 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8888 value = CompileRun(apply_99);
8889 CHECK(!try_catch.HasCaught());
8890 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008891
lrn@chromium.org1c092762011-05-09 09:42:16 +00008892 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8893 value = CompileRun(call_17);
8894 CHECK(!try_catch.HasCaught());
8895 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008896
lrn@chromium.org1c092762011-05-09 09:42:16 +00008897 // Check that the call-as-function handler can be called through
8898 // new.
8899 value = CompileRun("new obj(43)");
8900 CHECK(!try_catch.HasCaught());
8901 CHECK_EQ(-43, value->Int32Value());
8902
8903 // Check that the call-as-function handler can be called through
8904 // the API.
8905 v8::Handle<Value> args[] = { v8_num(28) };
8906 value = instance->CallAsFunction(instance, 1, args);
8907 CHECK(!try_catch.HasCaught());
8908 CHECK_EQ(28, value->Int32Value());
8909 }
8910
8911 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008912 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008913 USE(instance_template);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008914 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8915 context->Global()->Set(v8_str("obj2"), instance);
8916 v8::TryCatch try_catch;
8917 Local<Value> value;
8918 CHECK(!try_catch.HasCaught());
8919
8920 // Call an object without call-as-function handler through the JS
8921 value = CompileRun("obj2(28)");
8922 CHECK(value.IsEmpty());
8923 CHECK(try_catch.HasCaught());
8924 String::AsciiValue exception_value1(try_catch.Exception());
8925 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8926 *exception_value1);
8927 try_catch.Reset();
8928
8929 // Call an object without call-as-function handler through the API
8930 value = CompileRun("obj2(28)");
8931 v8::Handle<Value> args[] = { v8_num(28) };
8932 value = instance->CallAsFunction(instance, 1, args);
8933 CHECK(value.IsEmpty());
8934 CHECK(try_catch.HasCaught());
8935 String::AsciiValue exception_value2(try_catch.Exception());
8936 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8937 try_catch.Reset();
8938 }
8939
8940 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8941 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8942 instance_template->SetCallAsFunctionHandler(ThrowValue);
8943 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8944 context->Global()->Set(v8_str("obj3"), instance);
8945 v8::TryCatch try_catch;
8946 Local<Value> value;
8947 CHECK(!try_catch.HasCaught());
8948
8949 // Catch the exception which is thrown by call-as-function handler
8950 value = CompileRun("obj3(22)");
8951 CHECK(try_catch.HasCaught());
8952 String::AsciiValue exception_value1(try_catch.Exception());
8953 CHECK_EQ("22", *exception_value1);
8954 try_catch.Reset();
8955
8956 v8::Handle<Value> args[] = { v8_num(23) };
8957 value = instance->CallAsFunction(instance, 1, args);
8958 CHECK(try_catch.HasCaught());
8959 String::AsciiValue exception_value2(try_catch.Exception());
8960 CHECK_EQ("23", *exception_value2);
8961 try_catch.Reset();
8962 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008963}
8964
8965
karlklose@chromium.org83a47282011-05-11 11:54:09 +00008966// Check whether a non-function object is callable.
8967THREADED_TEST(CallableObject) {
8968 v8::HandleScope scope;
8969 LocalContext context;
8970
8971 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8972 instance_template->SetCallAsFunctionHandler(call_as_function);
8973 Local<Object> instance = instance_template->NewInstance();
8974 v8::TryCatch try_catch;
8975
8976 CHECK(instance->IsCallable());
8977 CHECK(!try_catch.HasCaught());
8978 }
8979
8980 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8981 Local<Object> instance = instance_template->NewInstance();
8982 v8::TryCatch try_catch;
8983
8984 CHECK(!instance->IsCallable());
8985 CHECK(!try_catch.HasCaught());
8986 }
8987
8988 { Local<FunctionTemplate> function_template =
8989 FunctionTemplate::New(call_as_function);
8990 Local<Function> function = function_template->GetFunction();
8991 Local<Object> instance = function;
8992 v8::TryCatch try_catch;
8993
8994 CHECK(instance->IsCallable());
8995 CHECK(!try_catch.HasCaught());
8996 }
8997
8998 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8999 Local<Function> function = function_template->GetFunction();
9000 Local<Object> instance = function;
9001 v8::TryCatch try_catch;
9002
9003 CHECK(instance->IsCallable());
9004 CHECK(!try_catch.HasCaught());
9005 }
9006}
9007
9008
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009009static int CountHandles() {
9010 return v8::HandleScope::NumberOfHandles();
9011}
9012
9013
9014static int Recurse(int depth, int iterations) {
9015 v8::HandleScope scope;
9016 if (depth == 0) return CountHandles();
9017 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009018 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009019 }
9020 return Recurse(depth - 1, iterations);
9021}
9022
9023
9024THREADED_TEST(HandleIteration) {
9025 static const int kIterations = 500;
9026 static const int kNesting = 200;
9027 CHECK_EQ(0, CountHandles());
9028 {
9029 v8::HandleScope scope1;
9030 CHECK_EQ(0, CountHandles());
9031 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009032 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009033 CHECK_EQ(i + 1, CountHandles());
9034 }
9035
9036 CHECK_EQ(kIterations, CountHandles());
9037 {
9038 v8::HandleScope scope2;
9039 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009040 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009041 CHECK_EQ(j + 1 + kIterations, CountHandles());
9042 }
9043 }
9044 CHECK_EQ(kIterations, CountHandles());
9045 }
9046 CHECK_EQ(0, CountHandles());
9047 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
9048}
9049
9050
9051static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
9052 Local<String> name,
9053 const AccessorInfo& info) {
9054 ApiTestFuzzer::Fuzz();
9055 return v8::Handle<Value>();
9056}
9057
9058
9059THREADED_TEST(InterceptorHasOwnProperty) {
9060 v8::HandleScope scope;
9061 LocalContext context;
9062 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9063 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
9064 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
9065 Local<Function> function = fun_templ->GetFunction();
9066 context->Global()->Set(v8_str("constructor"), function);
9067 v8::Handle<Value> value = CompileRun(
9068 "var o = new constructor();"
9069 "o.hasOwnProperty('ostehaps');");
9070 CHECK_EQ(false, value->BooleanValue());
9071 value = CompileRun(
9072 "o.ostehaps = 42;"
9073 "o.hasOwnProperty('ostehaps');");
9074 CHECK_EQ(true, value->BooleanValue());
9075 value = CompileRun(
9076 "var p = new constructor();"
9077 "p.hasOwnProperty('ostehaps');");
9078 CHECK_EQ(false, value->BooleanValue());
9079}
9080
9081
ager@chromium.org9085a012009-05-11 19:22:57 +00009082static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
9083 Local<String> name,
9084 const AccessorInfo& info) {
9085 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009086 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00009087 return v8::Handle<Value>();
9088}
9089
9090
9091THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
9092 v8::HandleScope scope;
9093 LocalContext context;
9094 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9095 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
9096 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
9097 Local<Function> function = fun_templ->GetFunction();
9098 context->Global()->Set(v8_str("constructor"), function);
9099 // Let's first make some stuff so we can be sure to get a good GC.
9100 CompileRun(
9101 "function makestr(size) {"
9102 " switch (size) {"
9103 " case 1: return 'f';"
9104 " case 2: return 'fo';"
9105 " case 3: return 'foo';"
9106 " }"
9107 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
9108 "}"
9109 "var x = makestr(12345);"
9110 "x = makestr(31415);"
9111 "x = makestr(23456);");
9112 v8::Handle<Value> value = CompileRun(
9113 "var o = new constructor();"
9114 "o.__proto__ = new String(x);"
9115 "o.hasOwnProperty('ostehaps');");
9116 CHECK_EQ(false, value->BooleanValue());
9117}
9118
9119
ager@chromium.orge2902be2009-06-08 12:21:35 +00009120typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
9121 const AccessorInfo& info);
9122
9123
9124static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
9125 const char* source,
9126 int expected) {
9127 v8::HandleScope scope;
9128 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009129 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00009130 LocalContext context;
9131 context->Global()->Set(v8_str("o"), templ->NewInstance());
9132 v8::Handle<Value> value = CompileRun(source);
9133 CHECK_EQ(expected, value->Int32Value());
9134}
9135
9136
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009137static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
9138 const AccessorInfo& info) {
9139 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009140 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9141 CHECK_EQ(isolate, info.GetIsolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009142 CHECK_EQ(v8_str("data"), info.Data());
9143 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009144 return v8::Integer::New(42);
9145}
9146
9147
9148// This test should hit the load IC for the interceptor case.
9149THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00009150 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009151 "var result = 0;"
9152 "for (var i = 0; i < 1000; i++) {"
9153 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00009154 "}",
9155 42);
9156}
9157
9158
9159// Below go several tests which verify that JITing for various
9160// configurations of interceptor and explicit fields works fine
9161// (those cases are special cased to get better performance).
9162
9163static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
9164 const AccessorInfo& info) {
9165 ApiTestFuzzer::Fuzz();
9166 return v8_str("x")->Equals(name)
9167 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
9168}
9169
9170
9171THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
9172 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9173 "var result = 0;"
9174 "o.y = 239;"
9175 "for (var i = 0; i < 1000; i++) {"
9176 " result = o.y;"
9177 "}",
9178 239);
9179}
9180
9181
9182THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
9183 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9184 "var result = 0;"
9185 "o.__proto__ = { 'y': 239 };"
9186 "for (var i = 0; i < 1000; i++) {"
9187 " result = o.y + o.x;"
9188 "}",
9189 239 + 42);
9190}
9191
9192
9193THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
9194 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9195 "var result = 0;"
9196 "o.__proto__.y = 239;"
9197 "for (var i = 0; i < 1000; i++) {"
9198 " result = o.y + o.x;"
9199 "}",
9200 239 + 42);
9201}
9202
9203
9204THREADED_TEST(InterceptorLoadICUndefined) {
9205 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9206 "var result = 0;"
9207 "for (var i = 0; i < 1000; i++) {"
9208 " result = (o.y == undefined) ? 239 : 42;"
9209 "}",
9210 239);
9211}
9212
9213
9214THREADED_TEST(InterceptorLoadICWithOverride) {
9215 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9216 "fst = new Object(); fst.__proto__ = o;"
9217 "snd = new Object(); snd.__proto__ = fst;"
9218 "var result1 = 0;"
9219 "for (var i = 0; i < 1000; i++) {"
9220 " result1 = snd.x;"
9221 "}"
9222 "fst.x = 239;"
9223 "var result = 0;"
9224 "for (var i = 0; i < 1000; i++) {"
9225 " result = snd.x;"
9226 "}"
9227 "result + result1",
9228 239 + 42);
9229}
9230
9231
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009232// Test the case when we stored field into
9233// a stub, but interceptor produced value on its own.
9234THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
9235 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9236 "proto = new Object();"
9237 "o.__proto__ = proto;"
9238 "proto.x = 239;"
9239 "for (var i = 0; i < 1000; i++) {"
9240 " o.x;"
9241 // Now it should be ICed and keep a reference to x defined on proto
9242 "}"
9243 "var result = 0;"
9244 "for (var i = 0; i < 1000; i++) {"
9245 " result += o.x;"
9246 "}"
9247 "result;",
9248 42 * 1000);
9249}
9250
9251
9252// Test the case when we stored field into
9253// a stub, but it got invalidated later on.
9254THREADED_TEST(InterceptorLoadICInvalidatedField) {
9255 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9256 "proto1 = new Object();"
9257 "proto2 = new Object();"
9258 "o.__proto__ = proto1;"
9259 "proto1.__proto__ = proto2;"
9260 "proto2.y = 239;"
9261 "for (var i = 0; i < 1000; i++) {"
9262 " o.y;"
9263 // Now it should be ICed and keep a reference to y defined on proto2
9264 "}"
9265 "proto1.y = 42;"
9266 "var result = 0;"
9267 "for (var i = 0; i < 1000; i++) {"
9268 " result += o.y;"
9269 "}"
9270 "result;",
9271 42 * 1000);
9272}
9273
9274
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00009275static int interceptor_load_not_handled_calls = 0;
9276static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
9277 const AccessorInfo& info) {
9278 ++interceptor_load_not_handled_calls;
9279 return v8::Handle<v8::Value>();
9280}
9281
9282
9283// Test how post-interceptor lookups are done in the non-cacheable
9284// case: the interceptor should not be invoked during this lookup.
9285THREADED_TEST(InterceptorLoadICPostInterceptor) {
9286 interceptor_load_not_handled_calls = 0;
9287 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
9288 "receiver = new Object();"
9289 "receiver.__proto__ = o;"
9290 "proto = new Object();"
9291 "/* Make proto a slow-case object. */"
9292 "for (var i = 0; i < 1000; i++) {"
9293 " proto[\"xxxxxxxx\" + i] = [];"
9294 "}"
9295 "proto.x = 17;"
9296 "o.__proto__ = proto;"
9297 "var result = 0;"
9298 "for (var i = 0; i < 1000; i++) {"
9299 " result += receiver.x;"
9300 "}"
9301 "result;",
9302 17 * 1000);
9303 CHECK_EQ(1000, interceptor_load_not_handled_calls);
9304}
9305
9306
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009307// Test the case when we stored field into
9308// a stub, but it got invalidated later on due to override on
9309// global object which is between interceptor and fields' holders.
9310THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
9311 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9312 "o.__proto__ = this;" // set a global to be a proto of o.
9313 "this.__proto__.y = 239;"
9314 "for (var i = 0; i < 10; i++) {"
9315 " if (o.y != 239) throw 'oops: ' + o.y;"
9316 // Now it should be ICed and keep a reference to y defined on field_holder.
9317 "}"
9318 "this.y = 42;" // Assign on a global.
9319 "var result = 0;"
9320 "for (var i = 0; i < 10; i++) {"
9321 " result += o.y;"
9322 "}"
9323 "result;",
9324 42 * 10);
9325}
9326
9327
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009328static void SetOnThis(Local<String> name,
9329 Local<Value> value,
9330 const AccessorInfo& info) {
9331 info.This()->ForceSet(name, value);
9332}
9333
9334
9335THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
9336 v8::HandleScope scope;
9337 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9338 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9339 templ->SetAccessor(v8_str("y"), Return239);
9340 LocalContext context;
9341 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009342
9343 // Check the case when receiver and interceptor's holder
9344 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009345 v8::Handle<Value> value = CompileRun(
9346 "var result = 0;"
9347 "for (var i = 0; i < 7; i++) {"
9348 " result = o.y;"
9349 "}");
9350 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009351
9352 // Check the case when interceptor's holder is in proto chain
9353 // of receiver.
9354 value = CompileRun(
9355 "r = { __proto__: o };"
9356 "var result = 0;"
9357 "for (var i = 0; i < 7; i++) {"
9358 " result = r.y;"
9359 "}");
9360 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009361}
9362
9363
9364THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
9365 v8::HandleScope scope;
9366 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9367 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9368 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9369 templ_p->SetAccessor(v8_str("y"), Return239);
9370
9371 LocalContext context;
9372 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9373 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9374
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009375 // Check the case when receiver and interceptor's holder
9376 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009377 v8::Handle<Value> value = CompileRun(
9378 "o.__proto__ = p;"
9379 "var result = 0;"
9380 "for (var i = 0; i < 7; i++) {"
9381 " result = o.x + o.y;"
9382 "}");
9383 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009384
9385 // Check the case when interceptor's holder is in proto chain
9386 // of receiver.
9387 value = CompileRun(
9388 "r = { __proto__: o };"
9389 "var result = 0;"
9390 "for (var i = 0; i < 7; i++) {"
9391 " result = r.x + r.y;"
9392 "}");
9393 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009394}
9395
9396
9397THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
9398 v8::HandleScope scope;
9399 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9400 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9401 templ->SetAccessor(v8_str("y"), Return239);
9402
9403 LocalContext context;
9404 context->Global()->Set(v8_str("o"), templ->NewInstance());
9405
9406 v8::Handle<Value> value = CompileRun(
9407 "fst = new Object(); fst.__proto__ = o;"
9408 "snd = new Object(); snd.__proto__ = fst;"
9409 "var result1 = 0;"
9410 "for (var i = 0; i < 7; i++) {"
9411 " result1 = snd.x;"
9412 "}"
9413 "fst.x = 239;"
9414 "var result = 0;"
9415 "for (var i = 0; i < 7; i++) {"
9416 " result = snd.x;"
9417 "}"
9418 "result + result1");
9419 CHECK_EQ(239 + 42, value->Int32Value());
9420}
9421
9422
9423// Test the case when we stored callback into
9424// a stub, but interceptor produced value on its own.
9425THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
9426 v8::HandleScope scope;
9427 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9428 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9429 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9430 templ_p->SetAccessor(v8_str("y"), Return239);
9431
9432 LocalContext context;
9433 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9434 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9435
9436 v8::Handle<Value> value = CompileRun(
9437 "o.__proto__ = p;"
9438 "for (var i = 0; i < 7; i++) {"
9439 " o.x;"
9440 // Now it should be ICed and keep a reference to x defined on p
9441 "}"
9442 "var result = 0;"
9443 "for (var i = 0; i < 7; i++) {"
9444 " result += o.x;"
9445 "}"
9446 "result");
9447 CHECK_EQ(42 * 7, value->Int32Value());
9448}
9449
9450
9451// Test the case when we stored callback into
9452// a stub, but it got invalidated later on.
9453THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
9454 v8::HandleScope scope;
9455 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9456 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9457 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9458 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9459
9460 LocalContext context;
9461 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9462 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9463
9464 v8::Handle<Value> value = CompileRun(
9465 "inbetween = new Object();"
9466 "o.__proto__ = inbetween;"
9467 "inbetween.__proto__ = p;"
9468 "for (var i = 0; i < 10; i++) {"
9469 " o.y;"
9470 // Now it should be ICed and keep a reference to y defined on p
9471 "}"
9472 "inbetween.y = 42;"
9473 "var result = 0;"
9474 "for (var i = 0; i < 10; i++) {"
9475 " result += o.y;"
9476 "}"
9477 "result");
9478 CHECK_EQ(42 * 10, value->Int32Value());
9479}
9480
9481
9482// Test the case when we stored callback into
9483// a stub, but it got invalidated later on due to override on
9484// global object which is between interceptor and callbacks' holders.
9485THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
9486 v8::HandleScope scope;
9487 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9488 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9489 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9490 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9491
9492 LocalContext context;
9493 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9494 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9495
9496 v8::Handle<Value> value = CompileRun(
9497 "o.__proto__ = this;"
9498 "this.__proto__ = p;"
9499 "for (var i = 0; i < 10; i++) {"
9500 " if (o.y != 239) throw 'oops: ' + o.y;"
9501 // Now it should be ICed and keep a reference to y defined on p
9502 "}"
9503 "this.y = 42;"
9504 "var result = 0;"
9505 "for (var i = 0; i < 10; i++) {"
9506 " result += o.y;"
9507 "}"
9508 "result");
9509 CHECK_EQ(42 * 10, value->Int32Value());
9510}
9511
9512
ager@chromium.orge2902be2009-06-08 12:21:35 +00009513static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9514 const AccessorInfo& info) {
9515 ApiTestFuzzer::Fuzz();
9516 CHECK(v8_str("x")->Equals(name));
9517 return v8::Integer::New(0);
9518}
9519
9520
9521THREADED_TEST(InterceptorReturningZero) {
9522 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9523 "o.x == undefined ? 1 : 0",
9524 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009525}
9526
9527
9528static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009529 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009530 CHECK(v8_str("x")->Equals(key));
9531 CHECK_EQ(42, value->Int32Value());
9532 return value;
9533}
9534
9535
9536// This test should hit the store IC for the interceptor case.
9537THREADED_TEST(InterceptorStoreIC) {
9538 v8::HandleScope scope;
9539 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9540 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009541 InterceptorStoreICSetter,
9542 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009543 LocalContext context;
9544 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009545 CompileRun(
9546 "for (var i = 0; i < 1000; i++) {"
9547 " o.x = 42;"
9548 "}");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009549}
9550
9551
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009552THREADED_TEST(InterceptorStoreICWithNoSetter) {
9553 v8::HandleScope scope;
9554 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9555 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9556 LocalContext context;
9557 context->Global()->Set(v8_str("o"), templ->NewInstance());
9558 v8::Handle<Value> value = CompileRun(
9559 "for (var i = 0; i < 1000; i++) {"
9560 " o.y = 239;"
9561 "}"
9562 "42 + o.y");
9563 CHECK_EQ(239 + 42, value->Int32Value());
9564}
9565
9566
9567
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009568
9569v8::Handle<Value> call_ic_function;
9570v8::Handle<Value> call_ic_function2;
9571v8::Handle<Value> call_ic_function3;
9572
9573static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9574 const AccessorInfo& info) {
9575 ApiTestFuzzer::Fuzz();
9576 CHECK(v8_str("x")->Equals(name));
9577 return call_ic_function;
9578}
9579
9580
9581// This test should hit the call IC for the interceptor case.
9582THREADED_TEST(InterceptorCallIC) {
9583 v8::HandleScope scope;
9584 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9585 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9586 LocalContext context;
9587 context->Global()->Set(v8_str("o"), templ->NewInstance());
9588 call_ic_function =
9589 v8_compile("function f(x) { return x + 1; }; f")->Run();
9590 v8::Handle<Value> value = CompileRun(
9591 "var result = 0;"
9592 "for (var i = 0; i < 1000; i++) {"
9593 " result = o.x(41);"
9594 "}");
9595 CHECK_EQ(42, value->Int32Value());
9596}
9597
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009598
9599// This test checks that if interceptor doesn't provide
9600// a value, we can fetch regular value.
9601THREADED_TEST(InterceptorCallICSeesOthers) {
9602 v8::HandleScope scope;
9603 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9604 templ->SetNamedPropertyHandler(NoBlockGetterX);
9605 LocalContext context;
9606 context->Global()->Set(v8_str("o"), templ->NewInstance());
9607 v8::Handle<Value> value = CompileRun(
9608 "o.x = function f(x) { return x + 1; };"
9609 "var result = 0;"
9610 "for (var i = 0; i < 7; i++) {"
9611 " result = o.x(41);"
9612 "}");
9613 CHECK_EQ(42, value->Int32Value());
9614}
9615
9616
9617static v8::Handle<Value> call_ic_function4;
9618static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9619 const AccessorInfo& info) {
9620 ApiTestFuzzer::Fuzz();
9621 CHECK(v8_str("x")->Equals(name));
9622 return call_ic_function4;
9623}
9624
9625
9626// This test checks that if interceptor provides a function,
9627// even if we cached shadowed variant, interceptor's function
9628// is invoked
9629THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9630 v8::HandleScope scope;
9631 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9632 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9633 LocalContext context;
9634 context->Global()->Set(v8_str("o"), templ->NewInstance());
9635 call_ic_function4 =
9636 v8_compile("function f(x) { return x - 1; }; f")->Run();
9637 v8::Handle<Value> value = CompileRun(
9638 "o.__proto__.x = function(x) { return x + 1; };"
9639 "var result = 0;"
9640 "for (var i = 0; i < 1000; i++) {"
9641 " result = o.x(42);"
9642 "}");
9643 CHECK_EQ(41, value->Int32Value());
9644}
9645
9646
9647// Test the case when we stored cacheable lookup into
9648// a stub, but it got invalidated later on
9649THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9650 v8::HandleScope scope;
9651 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9652 templ->SetNamedPropertyHandler(NoBlockGetterX);
9653 LocalContext context;
9654 context->Global()->Set(v8_str("o"), templ->NewInstance());
9655 v8::Handle<Value> value = CompileRun(
9656 "proto1 = new Object();"
9657 "proto2 = new Object();"
9658 "o.__proto__ = proto1;"
9659 "proto1.__proto__ = proto2;"
9660 "proto2.y = function(x) { return x + 1; };"
9661 // Invoke it many times to compile a stub
9662 "for (var i = 0; i < 7; i++) {"
9663 " o.y(42);"
9664 "}"
9665 "proto1.y = function(x) { return x - 1; };"
9666 "var result = 0;"
9667 "for (var i = 0; i < 7; i++) {"
9668 " result += o.y(42);"
9669 "}");
9670 CHECK_EQ(41 * 7, value->Int32Value());
9671}
9672
9673
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009674// This test checks that if interceptor doesn't provide a function,
9675// cached constant function is used
9676THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9677 v8::HandleScope scope;
9678 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9679 templ->SetNamedPropertyHandler(NoBlockGetterX);
9680 LocalContext context;
9681 context->Global()->Set(v8_str("o"), templ->NewInstance());
9682 v8::Handle<Value> value = CompileRun(
9683 "function inc(x) { return x + 1; };"
9684 "inc(1);"
9685 "o.x = inc;"
9686 "var result = 0;"
9687 "for (var i = 0; i < 1000; i++) {"
9688 " result = o.x(42);"
9689 "}");
9690 CHECK_EQ(43, value->Int32Value());
9691}
9692
9693
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009694static v8::Handle<Value> call_ic_function5;
9695static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9696 const AccessorInfo& info) {
9697 ApiTestFuzzer::Fuzz();
9698 if (v8_str("x")->Equals(name))
9699 return call_ic_function5;
9700 else
9701 return Local<Value>();
9702}
9703
9704
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009705// This test checks that if interceptor provides a function,
9706// even if we cached constant function, interceptor's function
9707// is invoked
9708THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9709 v8::HandleScope scope;
9710 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9711 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9712 LocalContext context;
9713 context->Global()->Set(v8_str("o"), templ->NewInstance());
9714 call_ic_function5 =
9715 v8_compile("function f(x) { return x - 1; }; f")->Run();
9716 v8::Handle<Value> value = CompileRun(
9717 "function inc(x) { return x + 1; };"
9718 "inc(1);"
9719 "o.x = inc;"
9720 "var result = 0;"
9721 "for (var i = 0; i < 1000; i++) {"
9722 " result = o.x(42);"
9723 "}");
9724 CHECK_EQ(41, value->Int32Value());
9725}
9726
9727
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009728static v8::Handle<Value> call_ic_function6;
9729static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9730 const AccessorInfo& info) {
9731 ApiTestFuzzer::Fuzz();
9732 if (v8_str("x")->Equals(name))
9733 return call_ic_function6;
9734 else
9735 return Local<Value>();
9736}
9737
9738
9739// Same test as above, except the code is wrapped in a function
9740// to test the optimized compiler.
9741THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9742 i::FLAG_allow_natives_syntax = true;
9743 v8::HandleScope scope;
9744 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9745 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9746 LocalContext context;
9747 context->Global()->Set(v8_str("o"), templ->NewInstance());
9748 call_ic_function6 =
9749 v8_compile("function f(x) { return x - 1; }; f")->Run();
9750 v8::Handle<Value> value = CompileRun(
9751 "function inc(x) { return x + 1; };"
9752 "inc(1);"
9753 "o.x = inc;"
9754 "function test() {"
9755 " var result = 0;"
9756 " for (var i = 0; i < 1000; i++) {"
9757 " result = o.x(42);"
9758 " }"
9759 " return result;"
9760 "};"
9761 "test();"
9762 "test();"
9763 "test();"
9764 "%OptimizeFunctionOnNextCall(test);"
9765 "test()");
9766 CHECK_EQ(41, value->Int32Value());
9767}
9768
9769
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009770// Test the case when we stored constant function into
9771// a stub, but it got invalidated later on
9772THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9773 v8::HandleScope scope;
9774 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9775 templ->SetNamedPropertyHandler(NoBlockGetterX);
9776 LocalContext context;
9777 context->Global()->Set(v8_str("o"), templ->NewInstance());
9778 v8::Handle<Value> value = CompileRun(
9779 "function inc(x) { return x + 1; };"
9780 "inc(1);"
9781 "proto1 = new Object();"
9782 "proto2 = new Object();"
9783 "o.__proto__ = proto1;"
9784 "proto1.__proto__ = proto2;"
9785 "proto2.y = inc;"
9786 // Invoke it many times to compile a stub
9787 "for (var i = 0; i < 7; i++) {"
9788 " o.y(42);"
9789 "}"
9790 "proto1.y = function(x) { return x - 1; };"
9791 "var result = 0;"
9792 "for (var i = 0; i < 7; i++) {"
9793 " result += o.y(42);"
9794 "}");
9795 CHECK_EQ(41 * 7, value->Int32Value());
9796}
9797
9798
9799// Test the case when we stored constant function into
9800// a stub, but it got invalidated later on due to override on
9801// global object which is between interceptor and constant function' holders.
9802THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9803 v8::HandleScope scope;
9804 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9805 templ->SetNamedPropertyHandler(NoBlockGetterX);
9806 LocalContext context;
9807 context->Global()->Set(v8_str("o"), templ->NewInstance());
9808 v8::Handle<Value> value = CompileRun(
9809 "function inc(x) { return x + 1; };"
9810 "inc(1);"
9811 "o.__proto__ = this;"
9812 "this.__proto__.y = inc;"
9813 // Invoke it many times to compile a stub
9814 "for (var i = 0; i < 7; i++) {"
9815 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9816 "}"
9817 "this.y = function(x) { return x - 1; };"
9818 "var result = 0;"
9819 "for (var i = 0; i < 7; i++) {"
9820 " result += o.y(42);"
9821 "}");
9822 CHECK_EQ(41 * 7, value->Int32Value());
9823}
9824
9825
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009826// Test the case when actual function to call sits on global object.
9827THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9828 v8::HandleScope scope;
9829 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9830 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9831
9832 LocalContext context;
9833 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9834
9835 v8::Handle<Value> value = CompileRun(
9836 "try {"
9837 " o.__proto__ = this;"
9838 " for (var i = 0; i < 10; i++) {"
9839 " var v = o.parseFloat('239');"
9840 " if (v != 239) throw v;"
9841 // Now it should be ICed and keep a reference to parseFloat.
9842 " }"
9843 " var result = 0;"
9844 " for (var i = 0; i < 10; i++) {"
9845 " result += o.parseFloat('239');"
9846 " }"
9847 " result"
9848 "} catch(e) {"
9849 " e"
9850 "};");
9851 CHECK_EQ(239 * 10, value->Int32Value());
9852}
9853
ager@chromium.org5c838252010-02-19 08:53:10 +00009854static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9855 const AccessorInfo& info) {
9856 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00009857 int* call_count =
9858 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
ager@chromium.org5c838252010-02-19 08:53:10 +00009859 ++(*call_count);
9860 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009861 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00009862 }
9863 return v8::Handle<Value>();
9864}
9865
9866static v8::Handle<Value> FastApiCallback_TrivialSignature(
9867 const v8::Arguments& args) {
9868 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009869 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9870 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009871 CHECK_EQ(args.This(), args.Holder());
9872 CHECK(args.Data()->Equals(v8_str("method_data")));
9873 return v8::Integer::New(args[0]->Int32Value() + 1);
9874}
9875
9876static v8::Handle<Value> FastApiCallback_SimpleSignature(
9877 const v8::Arguments& args) {
9878 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009879 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9880 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009881 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9882 CHECK(args.Data()->Equals(v8_str("method_data")));
9883 // Note, we're using HasRealNamedProperty instead of Has to avoid
9884 // invoking the interceptor again.
9885 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9886 return v8::Integer::New(args[0]->Int32Value() + 1);
9887}
9888
9889// Helper to maximize the odds of object moving.
9890static void GenerateSomeGarbage() {
9891 CompileRun(
9892 "var garbage;"
9893 "for (var i = 0; i < 1000; i++) {"
9894 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9895 "}"
9896 "garbage = undefined;");
9897}
9898
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009899
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009900v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9901 static int count = 0;
9902 if (count++ % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009903 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9904 // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009905 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9906 }
9907 return v8::Handle<v8::Value>();
9908}
9909
9910
9911THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9912 v8::HandleScope scope;
9913 LocalContext context;
9914 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9915 nativeobject_templ->Set("callback",
9916 v8::FunctionTemplate::New(DirectApiCallback));
9917 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9918 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9919 // call the api function multiple times to ensure direct call stub creation.
9920 CompileRun(
9921 "function f() {"
9922 " for (var i = 1; i <= 30; i++) {"
9923 " nativeobject.callback();"
9924 " }"
9925 "}"
9926 "f();");
9927}
9928
9929
9930v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9931 return v8::ThrowException(v8_str("g"));
9932}
9933
9934
9935THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9936 v8::HandleScope scope;
9937 LocalContext context;
9938 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9939 nativeobject_templ->Set("callback",
9940 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9941 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9942 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9943 // call the api function multiple times to ensure direct call stub creation.
9944 v8::Handle<Value> result = CompileRun(
9945 "var result = '';"
9946 "function f() {"
9947 " for (var i = 1; i <= 5; i++) {"
9948 " try { nativeobject.callback(); } catch (e) { result += e; }"
9949 " }"
9950 "}"
9951 "f(); result;");
9952 CHECK_EQ(v8_str("ggggg"), result);
9953}
9954
9955
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009956v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9957 const v8::AccessorInfo& info) {
9958 if (++p_getter_count % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009959 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009960 GenerateSomeGarbage();
9961 }
9962 return v8::Handle<v8::Value>();
9963}
9964
9965
9966THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9967 v8::HandleScope scope;
9968 LocalContext context;
9969 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9970 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9971 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9972 p_getter_count = 0;
9973 CompileRun(
9974 "function f() {"
9975 " for (var i = 0; i < 30; i++) o1.p1;"
9976 "}"
9977 "f();");
9978 CHECK_EQ(30, p_getter_count);
9979}
9980
9981
9982v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9983 Local<String> name, const v8::AccessorInfo& info) {
9984 return v8::ThrowException(v8_str("g"));
9985}
9986
9987
9988THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9989 v8::HandleScope scope;
9990 LocalContext context;
9991 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9992 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9993 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9994 v8::Handle<Value> result = CompileRun(
9995 "var result = '';"
9996 "for (var i = 0; i < 5; i++) {"
9997 " try { o1.p1; } catch (e) { result += e; }"
9998 "}"
9999 "result;");
10000 CHECK_EQ(v8_str("ggggg"), result);
10001}
10002
10003
ager@chromium.org5c838252010-02-19 08:53:10 +000010004THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10005 int interceptor_call_count = 0;
10006 v8::HandleScope scope;
10007 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10008 v8::Handle<v8::FunctionTemplate> method_templ =
10009 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10010 v8_str("method_data"),
10011 v8::Handle<v8::Signature>());
10012 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10013 proto_templ->Set(v8_str("method"), method_templ);
10014 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10015 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10016 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010017 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010018 LocalContext context;
10019 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10020 GenerateSomeGarbage();
10021 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010022 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010023 "var result = 0;"
10024 "for (var i = 0; i < 100; i++) {"
10025 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010026 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010027 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10028 CHECK_EQ(100, interceptor_call_count);
10029}
10030
10031THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10032 int interceptor_call_count = 0;
10033 v8::HandleScope scope;
10034 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10035 v8::Handle<v8::FunctionTemplate> method_templ =
10036 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10037 v8_str("method_data"),
10038 v8::Signature::New(fun_templ));
10039 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10040 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010041 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010042 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10043 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10044 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010045 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010046 LocalContext context;
10047 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10048 GenerateSomeGarbage();
10049 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010050 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010051 "o.foo = 17;"
10052 "var receiver = {};"
10053 "receiver.__proto__ = o;"
10054 "var result = 0;"
10055 "for (var i = 0; i < 100; i++) {"
10056 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010057 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010058 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10059 CHECK_EQ(100, interceptor_call_count);
10060}
10061
10062THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10063 int interceptor_call_count = 0;
10064 v8::HandleScope scope;
10065 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10066 v8::Handle<v8::FunctionTemplate> method_templ =
10067 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10068 v8_str("method_data"),
10069 v8::Signature::New(fun_templ));
10070 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10071 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010072 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010073 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10074 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10075 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010076 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010077 LocalContext context;
10078 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10079 GenerateSomeGarbage();
10080 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010081 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010082 "o.foo = 17;"
10083 "var receiver = {};"
10084 "receiver.__proto__ = o;"
10085 "var result = 0;"
10086 "var saved_result = 0;"
10087 "for (var i = 0; i < 100; i++) {"
10088 " result = receiver.method(41);"
10089 " if (i == 50) {"
10090 " saved_result = result;"
10091 " receiver = {method: function(x) { return x - 1 }};"
10092 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010093 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010094 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10095 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10096 CHECK_GE(interceptor_call_count, 50);
10097}
10098
10099THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
10100 int interceptor_call_count = 0;
10101 v8::HandleScope scope;
10102 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10103 v8::Handle<v8::FunctionTemplate> method_templ =
10104 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10105 v8_str("method_data"),
10106 v8::Signature::New(fun_templ));
10107 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10108 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010109 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010110 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10111 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10112 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010113 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010114 LocalContext context;
10115 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10116 GenerateSomeGarbage();
10117 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010118 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010119 "o.foo = 17;"
10120 "var receiver = {};"
10121 "receiver.__proto__ = o;"
10122 "var result = 0;"
10123 "var saved_result = 0;"
10124 "for (var i = 0; i < 100; i++) {"
10125 " result = receiver.method(41);"
10126 " if (i == 50) {"
10127 " saved_result = result;"
10128 " o.method = function(x) { return x - 1 };"
10129 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010130 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010131 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10132 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10133 CHECK_GE(interceptor_call_count, 50);
10134}
10135
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010136THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10137 int interceptor_call_count = 0;
10138 v8::HandleScope scope;
10139 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10140 v8::Handle<v8::FunctionTemplate> method_templ =
10141 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10142 v8_str("method_data"),
10143 v8::Signature::New(fun_templ));
10144 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10145 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010146 fun_templ->SetHiddenPrototype(true);
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010147 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10148 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10149 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010150 v8::External::New(&interceptor_call_count));
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010151 LocalContext context;
10152 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10153 GenerateSomeGarbage();
10154 context->Global()->Set(v8_str("o"), fun->NewInstance());
10155 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010156 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010157 "o.foo = 17;"
10158 "var receiver = {};"
10159 "receiver.__proto__ = o;"
10160 "var result = 0;"
10161 "var saved_result = 0;"
10162 "for (var i = 0; i < 100; i++) {"
10163 " result = receiver.method(41);"
10164 " if (i == 50) {"
10165 " saved_result = result;"
10166 " receiver = 333;"
10167 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010168 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010169 CHECK(try_catch.HasCaught());
10170 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10171 try_catch.Exception()->ToString());
10172 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10173 CHECK_GE(interceptor_call_count, 50);
10174}
10175
ager@chromium.org5c838252010-02-19 08:53:10 +000010176THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10177 int interceptor_call_count = 0;
10178 v8::HandleScope scope;
10179 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10180 v8::Handle<v8::FunctionTemplate> method_templ =
10181 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10182 v8_str("method_data"),
10183 v8::Signature::New(fun_templ));
10184 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10185 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010186 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010187 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10188 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10189 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010190 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010191 LocalContext context;
10192 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10193 GenerateSomeGarbage();
10194 context->Global()->Set(v8_str("o"), fun->NewInstance());
10195 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010196 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010197 "o.foo = 17;"
10198 "var receiver = {};"
10199 "receiver.__proto__ = o;"
10200 "var result = 0;"
10201 "var saved_result = 0;"
10202 "for (var i = 0; i < 100; i++) {"
10203 " result = receiver.method(41);"
10204 " if (i == 50) {"
10205 " saved_result = result;"
10206 " receiver = {method: receiver.method};"
10207 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010208 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010209 CHECK(try_catch.HasCaught());
10210 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
10211 try_catch.Exception()->ToString());
10212 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10213 CHECK_GE(interceptor_call_count, 50);
10214}
10215
10216THREADED_TEST(CallICFastApi_TrivialSignature) {
10217 v8::HandleScope scope;
10218 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10219 v8::Handle<v8::FunctionTemplate> method_templ =
10220 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10221 v8_str("method_data"),
10222 v8::Handle<v8::Signature>());
10223 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10224 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010225 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010226 USE(templ);
ager@chromium.org5c838252010-02-19 08:53:10 +000010227 LocalContext context;
10228 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10229 GenerateSomeGarbage();
10230 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010231 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010232 "var result = 0;"
10233 "for (var i = 0; i < 100; i++) {"
10234 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010235 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010236
10237 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10238}
10239
10240THREADED_TEST(CallICFastApi_SimpleSignature) {
10241 v8::HandleScope scope;
10242 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10243 v8::Handle<v8::FunctionTemplate> method_templ =
10244 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10245 v8_str("method_data"),
10246 v8::Signature::New(fun_templ));
10247 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10248 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010249 fun_templ->SetHiddenPrototype(true);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010250 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010251 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010252 LocalContext context;
10253 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10254 GenerateSomeGarbage();
10255 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010256 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010257 "o.foo = 17;"
10258 "var receiver = {};"
10259 "receiver.__proto__ = o;"
10260 "var result = 0;"
10261 "for (var i = 0; i < 100; i++) {"
10262 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010263 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010264
10265 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10266}
10267
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010268THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010269 v8::HandleScope scope;
10270 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10271 v8::Handle<v8::FunctionTemplate> method_templ =
10272 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10273 v8_str("method_data"),
10274 v8::Signature::New(fun_templ));
10275 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10276 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010277 fun_templ->SetHiddenPrototype(true);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010278 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010279 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010280 LocalContext context;
10281 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10282 GenerateSomeGarbage();
10283 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010284 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010285 "o.foo = 17;"
10286 "var receiver = {};"
10287 "receiver.__proto__ = o;"
10288 "var result = 0;"
10289 "var saved_result = 0;"
10290 "for (var i = 0; i < 100; i++) {"
10291 " result = receiver.method(41);"
10292 " if (i == 50) {"
10293 " saved_result = result;"
10294 " receiver = {method: function(x) { return x - 1 }};"
10295 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010296 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010297 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10298 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10299}
10300
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010301THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10302 v8::HandleScope scope;
10303 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10304 v8::Handle<v8::FunctionTemplate> method_templ =
10305 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10306 v8_str("method_data"),
10307 v8::Signature::New(fun_templ));
10308 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10309 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010310 fun_templ->SetHiddenPrototype(true);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010311 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010312 CHECK(!templ.IsEmpty());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010313 LocalContext context;
10314 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10315 GenerateSomeGarbage();
10316 context->Global()->Set(v8_str("o"), fun->NewInstance());
10317 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010318 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010319 "o.foo = 17;"
10320 "var receiver = {};"
10321 "receiver.__proto__ = o;"
10322 "var result = 0;"
10323 "var saved_result = 0;"
10324 "for (var i = 0; i < 100; i++) {"
10325 " result = receiver.method(41);"
10326 " if (i == 50) {"
10327 " saved_result = result;"
10328 " receiver = 333;"
10329 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010330 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010331 CHECK(try_catch.HasCaught());
10332 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10333 try_catch.Exception()->ToString());
10334 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10335}
10336
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010337THREADED_TEST(CallICFastApi_SimpleSignature_TypeError) {
10338 v8::HandleScope scope;
10339 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10340 v8::Handle<v8::FunctionTemplate> method_templ =
10341 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10342 v8_str("method_data"),
10343 v8::Signature::New(fun_templ));
10344 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10345 proto_templ->Set(v8_str("method"), method_templ);
10346 fun_templ->SetHiddenPrototype(true);
10347 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10348 CHECK(!templ.IsEmpty());
10349 LocalContext context;
10350 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10351 GenerateSomeGarbage();
10352 context->Global()->Set(v8_str("o"), fun->NewInstance());
10353 v8::TryCatch try_catch;
10354 CompileRun(
10355 "o.foo = 17;"
10356 "var receiver = {};"
10357 "receiver.__proto__ = o;"
10358 "var result = 0;"
10359 "var saved_result = 0;"
10360 "for (var i = 0; i < 100; i++) {"
10361 " result = receiver.method(41);"
10362 " if (i == 50) {"
10363 " saved_result = result;"
10364 " receiver = Object.create(receiver);"
10365 " }"
10366 "}");
10367 CHECK(try_catch.HasCaught());
10368 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
10369 try_catch.Exception()->ToString());
10370 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10371}
10372
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010373
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010374v8::Handle<Value> keyed_call_ic_function;
10375
10376static v8::Handle<Value> InterceptorKeyedCallICGetter(
10377 Local<String> name, const AccessorInfo& info) {
10378 ApiTestFuzzer::Fuzz();
10379 if (v8_str("x")->Equals(name)) {
10380 return keyed_call_ic_function;
10381 }
10382 return v8::Handle<Value>();
10383}
10384
10385
10386// Test the case when we stored cacheable lookup into
10387// a stub, but the function name changed (to another cacheable function).
10388THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
10389 v8::HandleScope scope;
10390 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10391 templ->SetNamedPropertyHandler(NoBlockGetterX);
10392 LocalContext context;
10393 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010394 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010395 "proto = new Object();"
10396 "proto.y = function(x) { return x + 1; };"
10397 "proto.z = function(x) { return x - 1; };"
10398 "o.__proto__ = proto;"
10399 "var result = 0;"
10400 "var method = 'y';"
10401 "for (var i = 0; i < 10; i++) {"
10402 " if (i == 5) { method = 'z'; };"
10403 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010404 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010405 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10406}
10407
10408
10409// Test the case when we stored cacheable lookup into
10410// a stub, but the function name changed (and the new function is present
10411// both before and after the interceptor in the prototype chain).
10412THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
10413 v8::HandleScope scope;
10414 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10415 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10416 LocalContext context;
10417 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10418 keyed_call_ic_function =
10419 v8_compile("function f(x) { return x - 1; }; f")->Run();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010420 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010421 "o = new Object();"
10422 "proto2 = new Object();"
10423 "o.y = function(x) { return x + 1; };"
10424 "proto2.y = function(x) { return x + 2; };"
10425 "o.__proto__ = proto1;"
10426 "proto1.__proto__ = proto2;"
10427 "var result = 0;"
10428 "var method = 'x';"
10429 "for (var i = 0; i < 10; i++) {"
10430 " if (i == 5) { method = 'y'; };"
10431 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010432 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010433 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10434}
10435
10436
10437// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10438// on the global object.
10439THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
10440 v8::HandleScope scope;
10441 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10442 templ->SetNamedPropertyHandler(NoBlockGetterX);
10443 LocalContext context;
10444 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010445 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010446 "function inc(x) { return x + 1; };"
10447 "inc(1);"
10448 "function dec(x) { return x - 1; };"
10449 "dec(1);"
10450 "o.__proto__ = this;"
10451 "this.__proto__.x = inc;"
10452 "this.__proto__.y = dec;"
10453 "var result = 0;"
10454 "var method = 'x';"
10455 "for (var i = 0; i < 10; i++) {"
10456 " if (i == 5) { method = 'y'; };"
10457 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010458 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010459 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10460}
10461
10462
10463// Test the case when actual function to call sits on global object.
10464THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
10465 v8::HandleScope scope;
10466 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10467 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10468 LocalContext context;
10469 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10470
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010471 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010472 "function len(x) { return x.length; };"
10473 "o.__proto__ = this;"
10474 "var m = 'parseFloat';"
10475 "var result = 0;"
10476 "for (var i = 0; i < 10; i++) {"
10477 " if (i == 5) {"
10478 " m = 'len';"
10479 " saved_result = result;"
10480 " };"
10481 " result = o[m]('239');"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010482 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010483 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10484 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10485}
10486
10487// Test the map transition before the interceptor.
10488THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
10489 v8::HandleScope scope;
10490 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10491 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10492 LocalContext context;
10493 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10494
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010495 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010496 "var o = new Object();"
10497 "o.__proto__ = proto;"
10498 "o.method = function(x) { return x + 1; };"
10499 "var m = 'method';"
10500 "var result = 0;"
10501 "for (var i = 0; i < 10; i++) {"
10502 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10503 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010504 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010505 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10506}
10507
10508
10509// Test the map transition after the interceptor.
10510THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
10511 v8::HandleScope scope;
10512 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10513 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10514 LocalContext context;
10515 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10516
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010517 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010518 "var proto = new Object();"
10519 "o.__proto__ = proto;"
10520 "proto.method = function(x) { return x + 1; };"
10521 "var m = 'method';"
10522 "var result = 0;"
10523 "for (var i = 0; i < 10; i++) {"
10524 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10525 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010526 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010527 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10528}
10529
10530
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010531static int interceptor_call_count = 0;
10532
10533static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10534 const AccessorInfo& info) {
10535 ApiTestFuzzer::Fuzz();
10536 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10537 return call_ic_function2;
10538 }
10539 return v8::Handle<Value>();
10540}
10541
10542
10543// This test should hit load and call ICs for the interceptor case.
10544// Once in a while, the interceptor will reply that a property was not
10545// found in which case we should get a reference error.
10546THREADED_TEST(InterceptorICReferenceErrors) {
10547 v8::HandleScope scope;
10548 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10549 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10550 LocalContext context(0, templ, v8::Handle<Value>());
10551 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10552 v8::Handle<Value> value = CompileRun(
10553 "function f() {"
10554 " for (var i = 0; i < 1000; i++) {"
10555 " try { x; } catch(e) { return true; }"
10556 " }"
10557 " return false;"
10558 "};"
10559 "f();");
10560 CHECK_EQ(true, value->BooleanValue());
10561 interceptor_call_count = 0;
10562 value = CompileRun(
10563 "function g() {"
10564 " for (var i = 0; i < 1000; i++) {"
10565 " try { x(42); } catch(e) { return true; }"
10566 " }"
10567 " return false;"
10568 "};"
10569 "g();");
10570 CHECK_EQ(true, value->BooleanValue());
10571}
10572
10573
10574static int interceptor_ic_exception_get_count = 0;
10575
10576static v8::Handle<Value> InterceptorICExceptionGetter(
10577 Local<String> name,
10578 const AccessorInfo& info) {
10579 ApiTestFuzzer::Fuzz();
10580 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10581 return call_ic_function3;
10582 }
10583 if (interceptor_ic_exception_get_count == 20) {
10584 return v8::ThrowException(v8_num(42));
10585 }
10586 // Do not handle get for properties other than x.
10587 return v8::Handle<Value>();
10588}
10589
10590// Test interceptor load/call IC where the interceptor throws an
10591// exception once in a while.
10592THREADED_TEST(InterceptorICGetterExceptions) {
10593 interceptor_ic_exception_get_count = 0;
10594 v8::HandleScope scope;
10595 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10596 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10597 LocalContext context(0, templ, v8::Handle<Value>());
10598 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10599 v8::Handle<Value> value = CompileRun(
10600 "function f() {"
10601 " for (var i = 0; i < 100; i++) {"
10602 " try { x; } catch(e) { return true; }"
10603 " }"
10604 " return false;"
10605 "};"
10606 "f();");
10607 CHECK_EQ(true, value->BooleanValue());
10608 interceptor_ic_exception_get_count = 0;
10609 value = CompileRun(
10610 "function f() {"
10611 " for (var i = 0; i < 100; i++) {"
10612 " try { x(42); } catch(e) { return true; }"
10613 " }"
10614 " return false;"
10615 "};"
10616 "f();");
10617 CHECK_EQ(true, value->BooleanValue());
10618}
10619
10620
10621static int interceptor_ic_exception_set_count = 0;
10622
10623static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010624 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010625 ApiTestFuzzer::Fuzz();
10626 if (++interceptor_ic_exception_set_count > 20) {
10627 return v8::ThrowException(v8_num(42));
10628 }
10629 // Do not actually handle setting.
10630 return v8::Handle<Value>();
10631}
10632
10633// Test interceptor store IC where the interceptor throws an exception
10634// once in a while.
10635THREADED_TEST(InterceptorICSetterExceptions) {
10636 interceptor_ic_exception_set_count = 0;
10637 v8::HandleScope scope;
10638 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10639 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10640 LocalContext context(0, templ, v8::Handle<Value>());
10641 v8::Handle<Value> value = CompileRun(
10642 "function f() {"
10643 " for (var i = 0; i < 100; i++) {"
10644 " try { x = 42; } catch(e) { return true; }"
10645 " }"
10646 " return false;"
10647 "};"
10648 "f();");
10649 CHECK_EQ(true, value->BooleanValue());
10650}
10651
10652
10653// Test that we ignore null interceptors.
10654THREADED_TEST(NullNamedInterceptor) {
10655 v8::HandleScope scope;
10656 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10657 templ->SetNamedPropertyHandler(0);
10658 LocalContext context;
10659 templ->Set("x", v8_num(42));
10660 v8::Handle<v8::Object> obj = templ->NewInstance();
10661 context->Global()->Set(v8_str("obj"), obj);
10662 v8::Handle<Value> value = CompileRun("obj.x");
10663 CHECK(value->IsInt32());
10664 CHECK_EQ(42, value->Int32Value());
10665}
10666
10667
10668// Test that we ignore null interceptors.
10669THREADED_TEST(NullIndexedInterceptor) {
10670 v8::HandleScope scope;
10671 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10672 templ->SetIndexedPropertyHandler(0);
10673 LocalContext context;
10674 templ->Set("42", v8_num(42));
10675 v8::Handle<v8::Object> obj = templ->NewInstance();
10676 context->Global()->Set(v8_str("obj"), obj);
10677 v8::Handle<Value> value = CompileRun("obj[42]");
10678 CHECK(value->IsInt32());
10679 CHECK_EQ(42, value->Int32Value());
10680}
10681
10682
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010683THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10684 v8::HandleScope scope;
10685 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10686 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10687 LocalContext env;
10688 env->Global()->Set(v8_str("obj"),
10689 templ->GetFunction()->NewInstance());
10690 ExpectTrue("obj.x === 42");
10691 ExpectTrue("!obj.propertyIsEnumerable('x')");
10692}
10693
10694
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010695static Handle<Value> ThrowingGetter(Local<String> name,
10696 const AccessorInfo& info) {
10697 ApiTestFuzzer::Fuzz();
10698 ThrowException(Handle<Value>());
10699 return Undefined();
10700}
10701
10702
10703THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10704 HandleScope scope;
10705 LocalContext context;
10706
10707 Local<FunctionTemplate> templ = FunctionTemplate::New();
10708 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10709 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10710
10711 Local<Object> instance = templ->GetFunction()->NewInstance();
10712
10713 Local<Object> another = Object::New();
10714 another->SetPrototype(instance);
10715
10716 Local<Object> with_js_getter = CompileRun(
10717 "o = {};\n"
10718 "o.__defineGetter__('f', function() { throw undefined; });\n"
10719 "o\n").As<Object>();
10720 CHECK(!with_js_getter.IsEmpty());
10721
10722 TryCatch try_catch;
10723
10724 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10725 CHECK(try_catch.HasCaught());
10726 try_catch.Reset();
10727 CHECK(result.IsEmpty());
10728
10729 result = another->GetRealNamedProperty(v8_str("f"));
10730 CHECK(try_catch.HasCaught());
10731 try_catch.Reset();
10732 CHECK(result.IsEmpty());
10733
10734 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10735 CHECK(try_catch.HasCaught());
10736 try_catch.Reset();
10737 CHECK(result.IsEmpty());
10738
10739 result = another->Get(v8_str("f"));
10740 CHECK(try_catch.HasCaught());
10741 try_catch.Reset();
10742 CHECK(result.IsEmpty());
10743
10744 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10745 CHECK(try_catch.HasCaught());
10746 try_catch.Reset();
10747 CHECK(result.IsEmpty());
10748
10749 result = with_js_getter->Get(v8_str("f"));
10750 CHECK(try_catch.HasCaught());
10751 try_catch.Reset();
10752 CHECK(result.IsEmpty());
10753}
10754
10755
10756static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10757 TryCatch try_catch;
10758 // Verboseness is important: it triggers message delivery which can call into
10759 // external code.
10760 try_catch.SetVerbose(true);
10761 CompileRun("throw 'from JS';");
10762 CHECK(try_catch.HasCaught());
10763 CHECK(!i::Isolate::Current()->has_pending_exception());
10764 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10765 return Undefined();
10766}
10767
10768
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010769static int call_depth;
10770
10771
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010772static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10773 TryCatch try_catch;
10774}
10775
10776
10777static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010778 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010779}
10780
10781
10782static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010783 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010784}
10785
10786
10787static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10788 Handle<String> errorMessageString = message->Get();
10789 CHECK(!errorMessageString.IsEmpty());
10790 message->GetStackTrace();
10791 message->GetScriptResourceName();
10792}
10793
10794THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10795 HandleScope scope;
10796 LocalContext context;
10797
10798 Local<Function> func =
10799 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10800 context->Global()->Set(v8_str("func"), func);
10801
10802 MessageCallback callbacks[] =
10803 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10804 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10805 MessageCallback callback = callbacks[i];
10806 if (callback != NULL) {
10807 V8::AddMessageListener(callback);
10808 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +000010809 // Some small number to control number of times message handler should
10810 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010811 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010812 ExpectFalse(
10813 "var thrown = false;\n"
10814 "try { func(); } catch(e) { thrown = true; }\n"
10815 "thrown\n");
10816 if (callback != NULL) {
10817 V8::RemoveMessageListeners(callback);
10818 }
10819 }
10820}
10821
10822
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010823static v8::Handle<Value> ParentGetter(Local<String> name,
10824 const AccessorInfo& info) {
10825 ApiTestFuzzer::Fuzz();
10826 return v8_num(1);
10827}
10828
10829
10830static v8::Handle<Value> ChildGetter(Local<String> name,
10831 const AccessorInfo& info) {
10832 ApiTestFuzzer::Fuzz();
10833 return v8_num(42);
10834}
10835
10836
10837THREADED_TEST(Overriding) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010838 i::FLAG_es5_readonly = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010839 v8::HandleScope scope;
10840 LocalContext context;
10841
10842 // Parent template.
10843 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10844 Local<ObjectTemplate> parent_instance_templ =
10845 parent_templ->InstanceTemplate();
10846 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10847
10848 // Template that inherits from the parent template.
10849 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10850 Local<ObjectTemplate> child_instance_templ =
10851 child_templ->InstanceTemplate();
10852 child_templ->Inherit(parent_templ);
10853 // Override 'f'. The child version of 'f' should get called for child
10854 // instances.
10855 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10856 // Add 'g' twice. The 'g' added last should get called for instances.
10857 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10858 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10859
10860 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10861 // so 'h' can be shadowed on the instance object.
10862 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10863 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10864 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10865
10866 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10867 // but the attribute does not have effect because it is duplicated with
10868 // NULL setter.
10869 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10870 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10871
10872
10873
10874 // Instantiate the child template.
10875 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10876
10877 // Check that the child function overrides the parent one.
10878 context->Global()->Set(v8_str("o"), instance);
10879 Local<Value> value = v8_compile("o.f")->Run();
10880 // Check that the 'g' that was added last is hit.
10881 CHECK_EQ(42, value->Int32Value());
10882 value = v8_compile("o.g")->Run();
10883 CHECK_EQ(42, value->Int32Value());
10884
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010885 // Check that 'h' cannot be shadowed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010886 value = v8_compile("o.h = 3; o.h")->Run();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010887 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010888
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010889 // Check that 'i' cannot be shadowed or changed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010890 value = v8_compile("o.i = 3; o.i")->Run();
10891 CHECK_EQ(42, value->Int32Value());
10892}
10893
10894
10895static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10896 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +000010897 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010898}
10899
10900
10901THREADED_TEST(IsConstructCall) {
10902 v8::HandleScope scope;
10903
10904 // Function template with call handler.
10905 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10906 templ->SetCallHandler(IsConstructHandler);
10907
10908 LocalContext context;
10909
10910 context->Global()->Set(v8_str("f"), templ->GetFunction());
10911 Local<Value> value = v8_compile("f()")->Run();
10912 CHECK(!value->BooleanValue());
10913 value = v8_compile("new f()")->Run();
10914 CHECK(value->BooleanValue());
10915}
10916
10917
10918THREADED_TEST(ObjectProtoToString) {
10919 v8::HandleScope scope;
10920 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10921 templ->SetClassName(v8_str("MyClass"));
10922
10923 LocalContext context;
10924
10925 Local<String> customized_tostring = v8_str("customized toString");
10926
10927 // Replace Object.prototype.toString
10928 v8_compile("Object.prototype.toString = function() {"
10929 " return 'customized toString';"
10930 "}")->Run();
10931
10932 // Normal ToString call should call replaced Object.prototype.toString
10933 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10934 Local<String> value = instance->ToString();
10935 CHECK(value->IsString() && value->Equals(customized_tostring));
10936
10937 // ObjectProtoToString should not call replace toString function.
10938 value = instance->ObjectProtoToString();
10939 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10940
10941 // Check global
10942 value = context->Global()->ObjectProtoToString();
10943 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10944
10945 // Check ordinary object
10946 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010947 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010948 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10949}
10950
10951
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010952THREADED_TEST(ObjectGetConstructorName) {
10953 v8::HandleScope scope;
10954 LocalContext context;
10955 v8_compile("function Parent() {};"
10956 "function Child() {};"
10957 "Child.prototype = new Parent();"
10958 "var outer = { inner: function() { } };"
10959 "var p = new Parent();"
10960 "var c = new Child();"
10961 "var x = new outer.inner();")->Run();
10962
10963 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10964 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10965 v8_str("Parent")));
10966
10967 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10968 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10969 v8_str("Child")));
10970
10971 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10972 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10973 v8_str("outer.inner")));
10974}
10975
10976
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010977bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010978i::Semaphore* ApiTestFuzzer::all_tests_done_=
10979 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010980int ApiTestFuzzer::active_tests_;
10981int ApiTestFuzzer::tests_being_run_;
10982int ApiTestFuzzer::current_;
10983
10984
10985// We are in a callback and want to switch to another thread (if we
10986// are currently running the thread fuzzing test).
10987void ApiTestFuzzer::Fuzz() {
10988 if (!fuzzing_) return;
10989 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10990 test->ContextSwitch();
10991}
10992
10993
10994// Let the next thread go. Since it is also waiting on the V8 lock it may
10995// not start immediately.
10996bool ApiTestFuzzer::NextThread() {
10997 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010998 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010999 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011000 if (kLogThreading)
11001 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011002 return false;
11003 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011004 if (kLogThreading) {
11005 printf("Switch from %s to %s\n",
11006 test_name,
11007 RegisterThreadedTest::nth(test_position)->name());
11008 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011009 current_ = test_position;
11010 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
11011 return true;
11012}
11013
11014
11015void ApiTestFuzzer::Run() {
11016 // When it is our turn...
11017 gate_->Wait();
11018 {
11019 // ... get the V8 lock and start running the test.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011020 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011021 CallTest();
11022 }
11023 // This test finished.
11024 active_ = false;
11025 active_tests_--;
11026 // If it was the last then signal that fact.
11027 if (active_tests_ == 0) {
11028 all_tests_done_->Signal();
11029 } else {
11030 // Otherwise select a new test and start that.
11031 NextThread();
11032 }
11033}
11034
11035
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011036static unsigned linear_congruential_generator;
11037
11038
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011039void ApiTestFuzzer::SetUp(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011040 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011041 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000011042 int count = RegisterThreadedTest::count();
11043 int start = count * part / (LAST_PART + 1);
11044 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11045 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011046 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011047 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011048 }
11049 for (int i = 0; i < active_tests_; i++) {
11050 RegisterThreadedTest::nth(i)->fuzzer_->Start();
11051 }
11052}
11053
11054
11055static void CallTestNumber(int test_number) {
11056 (RegisterThreadedTest::nth(test_number)->callback())();
11057}
11058
11059
11060void ApiTestFuzzer::RunAllTests() {
11061 // Set off the first test.
11062 current_ = -1;
11063 NextThread();
11064 // Wait till they are all done.
11065 all_tests_done_->Wait();
11066}
11067
11068
11069int ApiTestFuzzer::GetNextTestNumber() {
11070 int next_test;
11071 do {
11072 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11073 linear_congruential_generator *= 1664525u;
11074 linear_congruential_generator += 1013904223u;
11075 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11076 return next_test;
11077}
11078
11079
11080void ApiTestFuzzer::ContextSwitch() {
11081 // If the new thread is the same as the current thread there is nothing to do.
11082 if (NextThread()) {
11083 // Now it can start.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011084 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011085 // Wait till someone starts us again.
11086 gate_->Wait();
11087 // And we're off.
11088 }
11089}
11090
11091
11092void ApiTestFuzzer::TearDown() {
11093 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000011094 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11095 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11096 if (fuzzer != NULL) fuzzer->Join();
11097 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011098}
11099
11100
11101// Lets not be needlessly self-referential.
11102TEST(Threading) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011103 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011104 ApiTestFuzzer::RunAllTests();
11105 ApiTestFuzzer::TearDown();
11106}
11107
11108TEST(Threading2) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011109 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011110 ApiTestFuzzer::RunAllTests();
11111 ApiTestFuzzer::TearDown();
11112}
11113
lrn@chromium.org1c092762011-05-09 09:42:16 +000011114TEST(Threading3) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011115 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000011116 ApiTestFuzzer::RunAllTests();
11117 ApiTestFuzzer::TearDown();
11118}
11119
11120TEST(Threading4) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011121 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000011122 ApiTestFuzzer::RunAllTests();
11123 ApiTestFuzzer::TearDown();
11124}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011125
11126void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011127 if (kLogThreading)
11128 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011129 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011130 if (kLogThreading)
11131 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011132}
11133
11134
11135static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011136 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011137 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011138 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011139 const char* code = "throw 7;";
11140 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011141 v8::Locker nested_locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011142 v8::HandleScope scope;
11143 v8::Handle<Value> exception;
11144 { v8::TryCatch try_catch;
11145 v8::Handle<Value> value = CompileRun(code);
11146 CHECK(value.IsEmpty());
11147 CHECK(try_catch.HasCaught());
11148 // Make sure to wrap the exception in a new handle because
11149 // the handle returned from the TryCatch is destroyed
11150 // when the TryCatch is destroyed.
11151 exception = Local<Value>::New(try_catch.Exception());
11152 }
11153 return v8::ThrowException(exception);
11154 }
11155}
11156
11157
11158static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011159 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011160 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011161 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011162 const char* code = "throw 7;";
11163 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011164 v8::Locker nested_locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011165 v8::HandleScope scope;
11166 v8::Handle<Value> value = CompileRun(code);
11167 CHECK(value.IsEmpty());
11168 return v8_str("foo");
11169 }
11170}
11171
11172
11173// These are locking tests that don't need to be run again
11174// as part of the locking aggregation tests.
11175TEST(NestedLockers) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011176 v8::Locker locker(CcTest::default_isolate());
11177 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011178 v8::HandleScope scope;
11179 LocalContext env;
11180 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
11181 Local<Function> fun = fun_templ->GetFunction();
11182 env->Global()->Set(v8_str("throw_in_js"), fun);
11183 Local<Script> script = v8_compile("(function () {"
11184 " try {"
11185 " throw_in_js();"
11186 " return 42;"
11187 " } catch (e) {"
11188 " return e * 13;"
11189 " }"
11190 "})();");
11191 CHECK_EQ(91, script->Run()->Int32Value());
11192}
11193
11194
11195// These are locking tests that don't need to be run again
11196// as part of the locking aggregation tests.
11197TEST(NestedLockersNoTryCatch) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011198 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011199 v8::HandleScope scope;
11200 LocalContext env;
11201 Local<v8::FunctionTemplate> fun_templ =
11202 v8::FunctionTemplate::New(ThrowInJSNoCatch);
11203 Local<Function> fun = fun_templ->GetFunction();
11204 env->Global()->Set(v8_str("throw_in_js"), fun);
11205 Local<Script> script = v8_compile("(function () {"
11206 " try {"
11207 " throw_in_js();"
11208 " return 42;"
11209 " } catch (e) {"
11210 " return e * 13;"
11211 " }"
11212 "})();");
11213 CHECK_EQ(91, script->Run()->Int32Value());
11214}
11215
11216
11217THREADED_TEST(RecursiveLocking) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011218 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011219 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011220 v8::Locker locker2(CcTest::default_isolate());
11221 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011222 }
11223}
11224
11225
11226static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
11227 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011228 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011229 return v8::Undefined();
11230}
11231
11232
11233THREADED_TEST(LockUnlockLock) {
11234 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011235 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011236 v8::HandleScope scope;
11237 LocalContext env;
11238 Local<v8::FunctionTemplate> fun_templ =
11239 v8::FunctionTemplate::New(UnlockForAMoment);
11240 Local<Function> fun = fun_templ->GetFunction();
11241 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11242 Local<Script> script = v8_compile("(function () {"
11243 " unlock_for_a_moment();"
11244 " return 42;"
11245 "})();");
11246 CHECK_EQ(42, script->Run()->Int32Value());
11247 }
11248 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011249 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011250 v8::HandleScope scope;
11251 LocalContext env;
11252 Local<v8::FunctionTemplate> fun_templ =
11253 v8::FunctionTemplate::New(UnlockForAMoment);
11254 Local<Function> fun = fun_templ->GetFunction();
11255 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11256 Local<Script> script = v8_compile("(function () {"
11257 " unlock_for_a_moment();"
11258 " return 42;"
11259 "})();");
11260 CHECK_EQ(42, script->Run()->Int32Value());
11261 }
11262}
11263
11264
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011265static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011266 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011267 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011268 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011269 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11270 if (object->IsJSGlobalObject()) count++;
11271 return count;
11272}
11273
11274
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011275static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011276 // We need to collect all garbage twice to be sure that everything
11277 // has been collected. This is because inline caches are cleared in
11278 // the first garbage collection but some of the maps have already
11279 // been marked at that point. Therefore some of the maps are not
11280 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011281 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11282 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011283 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011284#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011285 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011286#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011287 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011288}
11289
11290
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011291TEST(DontLeakGlobalObjects) {
11292 // Regression test for issues 1139850 and 1174891.
11293
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011294 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011295
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011296 for (int i = 0; i < 5; i++) {
11297 { v8::HandleScope scope;
11298 LocalContext context;
11299 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011300 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011301 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011302
11303 { v8::HandleScope scope;
11304 LocalContext context;
11305 v8_compile("Date")->Run();
11306 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011307 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011308 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011309
11310 { v8::HandleScope scope;
11311 LocalContext context;
11312 v8_compile("/aaa/")->Run();
11313 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011314 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011315 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011316
11317 { v8::HandleScope scope;
11318 const char* extension_list[] = { "v8/gc" };
11319 v8::ExtensionConfiguration extensions(1, extension_list);
11320 LocalContext context(&extensions);
11321 v8_compile("gc();")->Run();
11322 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011323 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011324 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011325 }
11326}
11327
11328
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011329v8::Persistent<v8::Object> some_object;
11330v8::Persistent<v8::Object> bad_handle;
11331
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011332void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011333 v8::HandleScope scope;
11334 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011335 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011336}
11337
11338
11339THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11340 LocalContext context;
11341
11342 v8::Persistent<v8::Object> handle1, handle2;
11343 {
11344 v8::HandleScope scope;
11345 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
11346 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11347 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11348 }
11349 // Note: order is implementation dependent alas: currently
11350 // global handle nodes are processed by PostGarbageCollectionProcessing
11351 // in reverse allocation order, so if second allocated handle is deleted,
11352 // weak callback of the first handle would be able to 'reallocate' it.
11353 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
11354 handle2.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011355 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011356}
11357
11358
11359v8::Persistent<v8::Object> to_be_disposed;
11360
11361void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
11362 to_be_disposed.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011363 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011364 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011365}
11366
11367
11368THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11369 LocalContext context;
11370
11371 v8::Persistent<v8::Object> handle1, handle2;
11372 {
11373 v8::HandleScope scope;
11374 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11375 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11376 }
11377 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
11378 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011379 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011380}
11381
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011382void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
11383 handle.Dispose();
11384}
11385
11386void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
11387 v8::HandleScope scope;
11388 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011389 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011390}
11391
11392
11393THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11394 LocalContext context;
11395
11396 v8::Persistent<v8::Object> handle1, handle2, handle3;
11397 {
11398 v8::HandleScope scope;
11399 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
11400 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11401 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11402 }
11403 handle2.MakeWeak(NULL, DisposingCallback);
11404 handle3.MakeWeak(NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011405 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011406}
11407
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011408
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011409THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011410 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011411
11412 const int nof = 2;
11413 const char* sources[nof] = {
11414 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11415 "Object()"
11416 };
11417
11418 for (int i = 0; i < nof; i++) {
11419 const char* source = sources[i];
11420 { v8::HandleScope scope;
11421 LocalContext context;
11422 CompileRun(source);
11423 }
11424 { v8::HandleScope scope;
11425 LocalContext context;
11426 CompileRun(source);
11427 }
11428 }
11429}
11430
11431
11432static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11433 v8::HandleScope inner;
11434 env->Enter();
11435 v8::Handle<Value> three = v8_num(3);
11436 v8::Handle<Value> value = inner.Close(three);
11437 env->Exit();
11438 return value;
11439}
11440
11441
11442THREADED_TEST(NestedHandleScopeAndContexts) {
11443 v8::HandleScope outer;
11444 v8::Persistent<Context> env = Context::New();
11445 env->Enter();
11446 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011447 v8::Handle<String> str(value->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011448 CHECK(!str.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011449 env->Exit();
11450 env.Dispose();
11451}
11452
11453
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011454static i::Handle<i::JSFunction>* foo_ptr = NULL;
11455static int foo_count = 0;
11456static i::Handle<i::JSFunction>* bar_ptr = NULL;
11457static int bar_count = 0;
11458
11459
11460static void entry_hook(uintptr_t function,
11461 uintptr_t return_addr_location) {
11462 i::Code* code = i::Code::GetCodeFromTargetAddress(
11463 reinterpret_cast<i::Address>(function));
11464 CHECK(code != NULL);
11465
11466 if (bar_ptr != NULL && code == (*bar_ptr)->code())
11467 ++bar_count;
11468
11469 if (foo_ptr != NULL && code == (*foo_ptr)->code())
11470 ++foo_count;
11471
11472 // TODO(siggi): Verify return_addr_location.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011473 // This can be done by capturing JitCodeEvents, but requires an ordered
11474 // collection.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011475}
11476
11477
11478static void RunLoopInNewEnv() {
11479 bar_ptr = NULL;
11480 foo_ptr = NULL;
11481
11482 v8::HandleScope outer;
11483 v8::Persistent<Context> env = Context::New();
11484 env->Enter();
11485
11486 const char* script =
11487 "function bar() {"
11488 " var sum = 0;"
11489 " for (i = 0; i < 100; ++i)"
11490 " sum = foo(i);"
11491 " return sum;"
11492 "}"
11493 "function foo(i) { return i * i; }";
11494 CompileRun(script);
11495 i::Handle<i::JSFunction> bar =
11496 i::Handle<i::JSFunction>::cast(
11497 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11498 ASSERT(*bar);
11499
11500 i::Handle<i::JSFunction> foo =
11501 i::Handle<i::JSFunction>::cast(
11502 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11503 ASSERT(*foo);
11504
11505 bar_ptr = &bar;
11506 foo_ptr = &foo;
11507
11508 v8::Handle<v8::Value> value = CompileRun("bar();");
11509 CHECK(value->IsNumber());
11510 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11511
11512 // Test the optimized codegen path.
11513 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11514 "bar();");
11515 CHECK(value->IsNumber());
11516 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11517
11518 env->Exit();
11519}
11520
11521
11522TEST(SetFunctionEntryHook) {
11523 i::FLAG_allow_natives_syntax = true;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011524 i::FLAG_use_inlining = false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011525
11526 // Test setting and resetting the entry hook.
11527 // Nulling it should always succeed.
11528 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11529
11530 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11531 // Setting a hook while one's active should fail.
11532 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11533
11534 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11535
11536 // Reset the entry count to zero and set the entry hook.
11537 bar_count = 0;
11538 foo_count = 0;
11539 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11540 RunLoopInNewEnv();
11541
11542 CHECK_EQ(2, bar_count);
11543 CHECK_EQ(200, foo_count);
11544
11545 // Clear the entry hook and count.
11546 bar_count = 0;
11547 foo_count = 0;
11548 v8::V8::SetFunctionEntryHook(NULL);
11549
11550 // Clear the compilation cache to make sure we don't reuse the
11551 // functions from the previous invocation.
11552 v8::internal::Isolate::Current()->compilation_cache()->Clear();
11553
11554 // Verify that entry hooking is now disabled.
11555 RunLoopInNewEnv();
11556 CHECK_EQ(0u, bar_count);
11557 CHECK_EQ(0u, foo_count);
11558}
11559
11560
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011561static i::HashMap* code_map = NULL;
11562static int saw_bar = 0;
11563static int move_events = 0;
11564
11565
11566static bool FunctionNameIs(const char* expected,
11567 const v8::JitCodeEvent* event) {
11568 // Log lines for functions are of the general form:
11569 // "LazyCompile:<type><function_name>", where the type is one of
11570 // "*", "~" or "".
11571 static const char kPreamble[] = "LazyCompile:";
11572 static size_t kPreambleLen = sizeof(kPreamble) - 1;
11573
11574 if (event->name.len < sizeof(kPreamble) - 1 ||
11575 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11576 return false;
11577 }
11578
11579 const char* tail = event->name.str + kPreambleLen;
11580 size_t tail_len = event->name.len - kPreambleLen;
11581 size_t expected_len = strlen(expected);
11582 if (tail_len == expected_len + 1) {
11583 if (*tail == '*' || *tail == '~') {
11584 --tail_len;
11585 ++tail;
11586 } else {
11587 return false;
11588 }
11589 }
11590
11591 if (tail_len != expected_len)
11592 return false;
11593
11594 return strncmp(tail, expected, expected_len) == 0;
11595}
11596
11597
11598static void event_handler(const v8::JitCodeEvent* event) {
11599 CHECK(event != NULL);
11600 CHECK(code_map != NULL);
11601
11602 switch (event->type) {
11603 case v8::JitCodeEvent::CODE_ADDED: {
11604 CHECK(event->code_start != NULL);
11605 CHECK_NE(0, static_cast<int>(event->code_len));
11606 CHECK(event->name.str != NULL);
11607 i::HashMap::Entry* entry =
11608 code_map->Lookup(event->code_start,
11609 i::ComputePointerHash(event->code_start),
11610 true);
11611 entry->value = reinterpret_cast<void*>(event->code_len);
11612
11613 if (FunctionNameIs("bar", event)) {
11614 ++saw_bar;
11615 }
11616 }
11617 break;
11618
11619 case v8::JitCodeEvent::CODE_MOVED: {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011620 uint32_t hash = i::ComputePointerHash(event->code_start);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011621 // We would like to never see code move that we haven't seen before,
11622 // but the code creation event does not happen until the line endings
11623 // have been calculated (this is so that we can report the line in the
11624 // script at which the function source is found, see
11625 // Compiler::RecordFunctionCompilation) and the line endings
11626 // calculations can cause a GC, which can move the newly created code
11627 // before its existence can be logged.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011628 i::HashMap::Entry* entry =
11629 code_map->Lookup(event->code_start, hash, false);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011630 if (entry != NULL) {
11631 ++move_events;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011632
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011633 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11634 code_map->Remove(event->code_start, hash);
11635
11636 entry = code_map->Lookup(event->new_code_start,
11637 i::ComputePointerHash(event->new_code_start),
11638 true);
11639 CHECK(entry != NULL);
11640 entry->value = reinterpret_cast<void*>(event->code_len);
11641 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011642 }
11643 break;
11644
11645 case v8::JitCodeEvent::CODE_REMOVED:
11646 // Object/code removal events are currently not dispatched from the GC.
11647 CHECK(false);
11648 break;
11649 default:
11650 // Impossible event.
11651 CHECK(false);
11652 break;
11653 }
11654}
11655
11656
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011657static bool MatchPointers(void* key1, void* key2) {
11658 return key1 == key2;
11659}
11660
11661
11662TEST(SetJitCodeEventHandler) {
11663 const char* script =
11664 "function bar() {"
11665 " var sum = 0;"
11666 " for (i = 0; i < 100; ++i)"
11667 " sum = foo(i);"
11668 " return sum;"
11669 "}"
11670 "function foo(i) { return i * i; };"
11671 "bar();";
11672
11673 // Run this test in a new isolate to make sure we don't
11674 // have remnants of state from other code.
11675 v8::Isolate* isolate = v8::Isolate::New();
11676 isolate->Enter();
11677
11678 {
11679 i::HashMap code(MatchPointers);
11680 code_map = &code;
11681
11682 saw_bar = 0;
11683 move_events = 0;
11684
11685 i::FLAG_stress_compaction = true;
11686 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11687
11688 v8::HandleScope scope;
11689 // Generate new code objects sparsely distributed across several
11690 // different fragmented code-space pages.
11691 const int kIterations = 10;
11692 for (int i = 0; i < kIterations; ++i) {
11693 LocalContext env;
11694
11695 v8::Handle<v8::Script> compiled_script;
11696 {
11697 i::AlwaysAllocateScope always_allocate;
11698 SimulateFullSpace(HEAP->code_space());
11699 compiled_script = v8_compile(script);
11700 }
11701 compiled_script->Run();
11702
11703 // Clear the compilation cache to get more wastage.
11704 ISOLATE->compilation_cache()->Clear();
11705 }
11706
11707 // Force code movement.
11708 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11709
11710 CHECK_LE(kIterations, saw_bar);
11711 CHECK_NE(0, move_events);
11712
11713 code_map = NULL;
11714 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11715 }
11716
11717 isolate->Exit();
11718 isolate->Dispose();
11719
11720 // Do this in a new isolate.
11721 isolate = v8::Isolate::New();
11722 isolate->Enter();
11723
11724 // Verify that we get callbacks for existing code objects when we
11725 // request enumeration of existing code.
11726 {
11727 v8::HandleScope scope;
11728 LocalContext env;
11729 CompileRun(script);
11730
11731 // Now get code through initial iteration.
11732 i::HashMap code(MatchPointers);
11733 code_map = &code;
11734
11735 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11736 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11737
11738 code_map = NULL;
11739
11740 // We expect that we got some events. Note that if we could get code removal
11741 // notifications, we could compare two collections, one created by listening
11742 // from the time of creation of an isolate, and the other by subscribing
11743 // with EnumExisting.
11744 CHECK_NE(0, code.occupancy());
11745 }
11746
11747 isolate->Exit();
11748 isolate->Dispose();
11749}
11750
11751
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011752static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11753
11754
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011755THREADED_TEST(ExternalAllocatedMemory) {
11756 v8::HandleScope outer;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011757 v8::Persistent<Context> env(Context::New());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011758 CHECK(!env.IsEmpty());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011759 const intptr_t kSize = 1024*1024;
11760 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
11761 cast(kSize));
11762 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
11763 cast(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011764}
11765
11766
11767THREADED_TEST(DisposeEnteredContext) {
11768 v8::HandleScope scope;
11769 LocalContext outer;
11770 { v8::Persistent<v8::Context> inner = v8::Context::New();
11771 inner->Enter();
11772 inner.Dispose();
11773 inner.Clear();
11774 inner->Exit();
11775 }
11776}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011777
11778
11779// Regression test for issue 54, object templates with internal fields
11780// but no accessors or interceptors did not get their internal field
11781// count set on instances.
11782THREADED_TEST(Regress54) {
11783 v8::HandleScope outer;
11784 LocalContext context;
11785 static v8::Persistent<v8::ObjectTemplate> templ;
11786 if (templ.IsEmpty()) {
11787 v8::HandleScope inner;
11788 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
11789 local->SetInternalFieldCount(1);
11790 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
11791 }
11792 v8::Handle<v8::Object> result = templ->NewInstance();
11793 CHECK_EQ(1, result->InternalFieldCount());
11794}
11795
11796
11797// If part of the threaded tests, this test makes ThreadingTest fail
11798// on mac.
11799TEST(CatchStackOverflow) {
11800 v8::HandleScope scope;
11801 LocalContext context;
11802 v8::TryCatch try_catch;
11803 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
11804 "function f() {"
11805 " return f();"
11806 "}"
11807 ""
11808 "f();"));
11809 v8::Handle<v8::Value> result = script->Run();
11810 CHECK(result.IsEmpty());
11811}
11812
11813
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011814static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11815 const char* resource_name,
11816 int line_offset) {
11817 v8::HandleScope scope;
11818 v8::TryCatch try_catch;
11819 v8::Handle<v8::Value> result = script->Run();
11820 CHECK(result.IsEmpty());
11821 CHECK(try_catch.HasCaught());
11822 v8::Handle<v8::Message> message = try_catch.Message();
11823 CHECK(!message.IsEmpty());
11824 CHECK_EQ(10 + line_offset, message->GetLineNumber());
11825 CHECK_EQ(91, message->GetStartPosition());
11826 CHECK_EQ(92, message->GetEndPosition());
11827 CHECK_EQ(2, message->GetStartColumn());
11828 CHECK_EQ(3, message->GetEndColumn());
11829 v8::String::AsciiValue line(message->GetSourceLine());
11830 CHECK_EQ(" throw 'nirk';", *line);
11831 v8::String::AsciiValue name(message->GetScriptResourceName());
11832 CHECK_EQ(resource_name, *name);
11833}
11834
11835
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011836THREADED_TEST(TryCatchSourceInfo) {
11837 v8::HandleScope scope;
11838 LocalContext context;
11839 v8::Handle<v8::String> source = v8::String::New(
11840 "function Foo() {\n"
11841 " return Bar();\n"
11842 "}\n"
11843 "\n"
11844 "function Bar() {\n"
11845 " return Baz();\n"
11846 "}\n"
11847 "\n"
11848 "function Baz() {\n"
11849 " throw 'nirk';\n"
11850 "}\n"
11851 "\n"
11852 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011853
11854 const char* resource_name;
11855 v8::Handle<v8::Script> script;
11856 resource_name = "test.js";
11857 script = v8::Script::Compile(source, v8::String::New(resource_name));
11858 CheckTryCatchSourceInfo(script, resource_name, 0);
11859
11860 resource_name = "test1.js";
11861 v8::ScriptOrigin origin1(v8::String::New(resource_name));
11862 script = v8::Script::Compile(source, &origin1);
11863 CheckTryCatchSourceInfo(script, resource_name, 0);
11864
11865 resource_name = "test2.js";
11866 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11867 script = v8::Script::Compile(source, &origin2);
11868 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011869}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011870
11871
11872THREADED_TEST(CompilationCache) {
11873 v8::HandleScope scope;
11874 LocalContext context;
11875 v8::Handle<v8::String> source0 = v8::String::New("1234");
11876 v8::Handle<v8::String> source1 = v8::String::New("1234");
11877 v8::Handle<v8::Script> script0 =
11878 v8::Script::Compile(source0, v8::String::New("test.js"));
11879 v8::Handle<v8::Script> script1 =
11880 v8::Script::Compile(source1, v8::String::New("test.js"));
11881 v8::Handle<v8::Script> script2 =
11882 v8::Script::Compile(source0); // different origin
11883 CHECK_EQ(1234, script0->Run()->Int32Value());
11884 CHECK_EQ(1234, script1->Run()->Int32Value());
11885 CHECK_EQ(1234, script2->Run()->Int32Value());
11886}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000011887
11888
11889static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11890 ApiTestFuzzer::Fuzz();
11891 return v8_num(42);
11892}
11893
11894
11895THREADED_TEST(CallbackFunctionName) {
11896 v8::HandleScope scope;
11897 LocalContext context;
11898 Local<ObjectTemplate> t = ObjectTemplate::New();
11899 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11900 context->Global()->Set(v8_str("obj"), t->NewInstance());
11901 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11902 CHECK(value->IsString());
11903 v8::String::AsciiValue name(value);
11904 CHECK_EQ("asdf", *name);
11905}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011906
11907
11908THREADED_TEST(DateAccess) {
11909 v8::HandleScope scope;
11910 LocalContext context;
11911 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11912 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011913 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011914}
11915
11916
11917void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011918 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011919 v8::Handle<v8::Array> props = obj->GetPropertyNames();
11920 CHECK_EQ(elmc, props->Length());
11921 for (int i = 0; i < elmc; i++) {
11922 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11923 CHECK_EQ(elmv[i], *elm);
11924 }
11925}
11926
11927
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011928void CheckOwnProperties(v8::Handle<v8::Value> val,
11929 int elmc,
11930 const char* elmv[]) {
11931 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11932 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11933 CHECK_EQ(elmc, props->Length());
11934 for (int i = 0; i < elmc; i++) {
11935 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11936 CHECK_EQ(elmv[i], *elm);
11937 }
11938}
11939
11940
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011941THREADED_TEST(PropertyEnumeration) {
11942 v8::HandleScope scope;
11943 LocalContext context;
11944 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11945 "var result = [];"
11946 "result[0] = {};"
11947 "result[1] = {a: 1, b: 2};"
11948 "result[2] = [1, 2, 3];"
11949 "var proto = {x: 1, y: 2, z: 3};"
11950 "var x = { __proto__: proto, w: 0, z: 1 };"
11951 "result[3] = x;"
11952 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011953 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011954 CHECK_EQ(4, elms->Length());
11955 int elmc0 = 0;
11956 const char** elmv0 = NULL;
11957 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011958 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011959 int elmc1 = 2;
11960 const char* elmv1[] = {"a", "b"};
11961 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011962 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011963 int elmc2 = 3;
11964 const char* elmv2[] = {"0", "1", "2"};
11965 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011966 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011967 int elmc3 = 4;
11968 const char* elmv3[] = {"w", "z", "x", "y"};
11969 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011970 int elmc4 = 2;
11971 const char* elmv4[] = {"w", "z"};
11972 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011973}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011975THREADED_TEST(PropertyEnumeration2) {
11976 v8::HandleScope scope;
11977 LocalContext context;
11978 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11979 "var result = [];"
11980 "result[0] = {};"
11981 "result[1] = {a: 1, b: 2};"
11982 "result[2] = [1, 2, 3];"
11983 "var proto = {x: 1, y: 2, z: 3};"
11984 "var x = { __proto__: proto, w: 0, z: 1 };"
11985 "result[3] = x;"
11986 "result;"))->Run();
11987 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11988 CHECK_EQ(4, elms->Length());
11989 int elmc0 = 0;
11990 const char** elmv0 = NULL;
11991 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11992
11993 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11994 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11995 CHECK_EQ(0, props->Length());
11996 for (uint32_t i = 0; i < props->Length(); i++) {
11997 printf("p[%d]\n", i);
11998 }
11999}
ager@chromium.org870a0b62008-11-04 11:43:05 +000012000
ager@chromium.org870a0b62008-11-04 11:43:05 +000012001static bool NamedSetAccessBlocker(Local<v8::Object> obj,
12002 Local<Value> name,
12003 v8::AccessType type,
12004 Local<Value> data) {
12005 return type != v8::ACCESS_SET;
12006}
12007
12008
12009static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
12010 uint32_t key,
12011 v8::AccessType type,
12012 Local<Value> data) {
12013 return type != v8::ACCESS_SET;
12014}
12015
12016
12017THREADED_TEST(DisableAccessChecksWhileConfiguring) {
12018 v8::HandleScope scope;
12019 LocalContext context;
12020 Local<ObjectTemplate> templ = ObjectTemplate::New();
12021 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
12022 IndexedSetAccessBlocker);
12023 templ->Set(v8_str("x"), v8::True());
12024 Local<v8::Object> instance = templ->NewInstance();
12025 context->Global()->Set(v8_str("obj"), instance);
12026 Local<Value> value = CompileRun("obj.x");
12027 CHECK(value->BooleanValue());
12028}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012029
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012030
ager@chromium.org32912102009-01-16 10:38:43 +000012031static bool NamedGetAccessBlocker(Local<v8::Object> obj,
12032 Local<Value> name,
12033 v8::AccessType type,
12034 Local<Value> data) {
12035 return false;
12036}
12037
12038
12039static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
12040 uint32_t key,
12041 v8::AccessType type,
12042 Local<Value> data) {
12043 return false;
12044}
12045
12046
12047
12048THREADED_TEST(AccessChecksReenabledCorrectly) {
12049 v8::HandleScope scope;
12050 LocalContext context;
12051 Local<ObjectTemplate> templ = ObjectTemplate::New();
12052 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12053 IndexedGetAccessBlocker);
12054 templ->Set(v8_str("a"), v8_str("a"));
12055 // Add more than 8 (see kMaxFastProperties) properties
12056 // so that the constructor will force copying map.
12057 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012058 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000012059 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012060 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000012061 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012062 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000012063 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012064 buf[2] = k;
12065 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000012066 templ->Set(v8_str(buf), v8::Number::New(k));
12067 }
12068 }
12069 }
12070
12071 Local<v8::Object> instance_1 = templ->NewInstance();
12072 context->Global()->Set(v8_str("obj_1"), instance_1);
12073
12074 Local<Value> value_1 = CompileRun("obj_1.a");
12075 CHECK(value_1->IsUndefined());
12076
12077 Local<v8::Object> instance_2 = templ->NewInstance();
12078 context->Global()->Set(v8_str("obj_2"), instance_2);
12079
12080 Local<Value> value_2 = CompileRun("obj_2.a");
12081 CHECK(value_2->IsUndefined());
12082}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012083
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012084
ager@chromium.org8bb60582008-12-11 12:02:20 +000012085// This tests that access check information remains on the global
12086// object template when creating contexts.
12087THREADED_TEST(AccessControlRepeatedContextCreation) {
12088 v8::HandleScope handle_scope;
12089 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12090 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
12091 IndexedSetAccessBlocker);
12092 i::Handle<i::ObjectTemplateInfo> internal_template =
12093 v8::Utils::OpenHandle(*global_template);
12094 CHECK(!internal_template->constructor()->IsUndefined());
12095 i::Handle<i::FunctionTemplateInfo> constructor(
12096 i::FunctionTemplateInfo::cast(internal_template->constructor()));
12097 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012098 v8::Persistent<Context> context0(Context::New(NULL, global_template));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012099 CHECK(!context0.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +000012100 CHECK(!constructor->access_check_info()->IsUndefined());
12101}
12102
12103
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012104THREADED_TEST(TurnOnAccessCheck) {
12105 v8::HandleScope handle_scope;
12106
12107 // Create an environment with access check to the global object disabled by
12108 // default.
12109 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12110 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12111 IndexedGetAccessBlocker,
12112 v8::Handle<v8::Value>(),
12113 false);
12114 v8::Persistent<Context> context = Context::New(NULL, global_template);
12115 Context::Scope context_scope(context);
12116
12117 // Set up a property and a number of functions.
12118 context->Global()->Set(v8_str("a"), v8_num(1));
12119 CompileRun("function f1() {return a;}"
12120 "function f2() {return a;}"
12121 "function g1() {return h();}"
12122 "function g2() {return h();}"
12123 "function h() {return 1;}");
12124 Local<Function> f1 =
12125 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12126 Local<Function> f2 =
12127 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12128 Local<Function> g1 =
12129 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12130 Local<Function> g2 =
12131 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12132 Local<Function> h =
12133 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12134
12135 // Get the global object.
12136 v8::Handle<v8::Object> global = context->Global();
12137
12138 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12139 // uses the runtime system to retreive property a whereas f2 uses global load
12140 // inline cache.
12141 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12142 for (int i = 0; i < 4; i++) {
12143 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12144 }
12145
12146 // Same for g1 and g2.
12147 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12148 for (int i = 0; i < 4; i++) {
12149 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12150 }
12151
12152 // Detach the global and turn on access check.
12153 context->DetachGlobal();
12154 context->Global()->TurnOnAccessCheck();
12155
12156 // Failing access check to property get results in undefined.
12157 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12158 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12159
12160 // Failing access check to function call results in exception.
12161 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12162 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12163
12164 // No failing access check when just returning a constant.
12165 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12166}
12167
12168
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012169static const char* kPropertyA = "a";
12170static const char* kPropertyH = "h";
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012171
12172static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
12173 Local<Value> name,
12174 v8::AccessType type,
12175 Local<Value> data) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012176 if (!name->IsString()) return false;
12177 i::Handle<i::String> name_handle =
12178 v8::Utils::OpenHandle(String::Cast(*name));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012179 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
12180 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012181}
12182
12183
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012184THREADED_TEST(TurnOnAccessCheckAndRecompile) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012185 v8::HandleScope handle_scope;
12186
12187 // Create an environment with access check to the global object disabled by
12188 // default. When the registered access checker will block access to properties
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012189 // a and h.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012190 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12191 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
12192 IndexedGetAccessBlocker,
12193 v8::Handle<v8::Value>(),
12194 false);
12195 v8::Persistent<Context> context = Context::New(NULL, global_template);
12196 Context::Scope context_scope(context);
12197
12198 // Set up a property and a number of functions.
12199 context->Global()->Set(v8_str("a"), v8_num(1));
12200 static const char* source = "function f1() {return a;}"
12201 "function f2() {return a;}"
12202 "function g1() {return h();}"
12203 "function g2() {return h();}"
12204 "function h() {return 1;}";
12205
12206 CompileRun(source);
12207 Local<Function> f1;
12208 Local<Function> f2;
12209 Local<Function> g1;
12210 Local<Function> g2;
12211 Local<Function> h;
12212 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12213 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12214 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12215 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12216 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12217
12218 // Get the global object.
12219 v8::Handle<v8::Object> global = context->Global();
12220
12221 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12222 // uses the runtime system to retreive property a whereas f2 uses global load
12223 // inline cache.
12224 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12225 for (int i = 0; i < 4; i++) {
12226 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12227 }
12228
12229 // Same for g1 and g2.
12230 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12231 for (int i = 0; i < 4; i++) {
12232 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12233 }
12234
12235 // Detach the global and turn on access check now blocking access to property
12236 // a and function h.
12237 context->DetachGlobal();
12238 context->Global()->TurnOnAccessCheck();
12239
12240 // Failing access check to property get results in undefined.
12241 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12242 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12243
12244 // Failing access check to function call results in exception.
12245 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12246 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12247
12248 // No failing access check when just returning a constant.
12249 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12250
12251 // Now compile the source again. And get the newly compiled functions, except
12252 // for h for which access is blocked.
12253 CompileRun(source);
12254 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12255 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12256 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12257 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12258 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
12259
12260 // Failing access check to property get results in undefined.
12261 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12262 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12263
12264 // Failing access check to function call results in exception.
12265 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12266 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12267}
12268
12269
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012270// This test verifies that pre-compilation (aka preparsing) can be called
12271// without initializing the whole VM. Thus we cannot run this test in a
12272// multi-threaded setup.
12273TEST(PreCompile) {
12274 // TODO(155): This test would break without the initialization of V8. This is
12275 // a workaround for now to make this test not fail.
12276 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012277 const char* script = "function foo(a) { return a+1; }";
12278 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012279 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012280 CHECK_NE(sd->Length(), 0);
12281 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012282 CHECK(!sd->HasError());
12283 delete sd;
12284}
12285
12286
12287TEST(PreCompileWithError) {
12288 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012289 const char* script = "function foo(a) { return 1 * * 2; }";
12290 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012291 v8::ScriptData::PreCompile(script, i::StrLength(script));
12292 CHECK(sd->HasError());
12293 delete sd;
12294}
12295
12296
12297TEST(Regress31661) {
12298 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012299 const char* script = " The Definintive Guide";
12300 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012301 v8::ScriptData::PreCompile(script, i::StrLength(script));
12302 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012303 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012304}
12305
12306
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012307// Tests that ScriptData can be serialized and deserialized.
12308TEST(PreCompileSerialization) {
12309 v8::V8::Initialize();
12310 const char* script = "function foo(a) { return a+1; }";
12311 v8::ScriptData* sd =
12312 v8::ScriptData::PreCompile(script, i::StrLength(script));
12313
12314 // Serialize.
12315 int serialized_data_length = sd->Length();
12316 char* serialized_data = i::NewArray<char>(serialized_data_length);
12317 memcpy(serialized_data, sd->Data(), serialized_data_length);
12318
12319 // Deserialize.
12320 v8::ScriptData* deserialized_sd =
12321 v8::ScriptData::New(serialized_data, serialized_data_length);
12322
12323 // Verify that the original is the same as the deserialized.
12324 CHECK_EQ(sd->Length(), deserialized_sd->Length());
12325 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
12326 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
12327
12328 delete sd;
12329 delete deserialized_sd;
12330}
12331
12332
12333// Attempts to deserialize bad data.
12334TEST(PreCompileDeserializationError) {
12335 v8::V8::Initialize();
12336 const char* data = "DONT CARE";
12337 int invalid_size = 3;
12338 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
12339
12340 CHECK_EQ(0, sd->Length());
12341
12342 delete sd;
12343}
12344
12345
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012346// Attempts to deserialize bad data.
12347TEST(PreCompileInvalidPreparseDataError) {
12348 v8::V8::Initialize();
12349 v8::HandleScope scope;
12350 LocalContext context;
12351
12352 const char* script = "function foo(){ return 5;}\n"
12353 "function bar(){ return 6 + 7;} foo();";
12354 v8::ScriptData* sd =
12355 v8::ScriptData::PreCompile(script, i::StrLength(script));
12356 CHECK(!sd->HasError());
12357 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000012358 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000012359 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012360 const int kFunctionEntryStartOffset = 0;
12361 const int kFunctionEntryEndOffset = 1;
12362 unsigned* sd_data =
12363 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012364
12365 // Overwrite function bar's end position with 0.
12366 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12367 v8::TryCatch try_catch;
12368
12369 Local<String> source = String::New(script);
12370 Local<Script> compiled_script = Script::New(source, NULL, sd);
12371 CHECK(try_catch.HasCaught());
12372 String::AsciiValue exception_value(try_catch.Message()->Get());
12373 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12374 *exception_value);
12375
12376 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012377
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012378 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012379 // will not be found when searching for it by position and we should fall
12380 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000012381 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12382 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012383 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12384 200;
12385 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012386 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012387
12388 delete sd;
12389}
12390
12391
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012392// Verifies that the Handle<String> and const char* versions of the API produce
12393// the same results (at least for one trivial case).
12394TEST(PreCompileAPIVariationsAreSame) {
12395 v8::V8::Initialize();
12396 v8::HandleScope scope;
12397
12398 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012399
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012400 v8::ScriptData* sd_from_cstring =
12401 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12402
12403 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012404 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012405 v8::String::NewExternal(resource));
12406
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012407 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12408 v8::String::New(cstring));
12409
12410 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012411 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012412 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012413 sd_from_cstring->Length()));
12414
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012415 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12416 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12417 sd_from_string->Data(),
12418 sd_from_cstring->Length()));
12419
12420
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012421 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012422 delete sd_from_external_string;
12423 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012424}
12425
12426
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012427// This tests that we do not allow dictionary load/call inline caches
12428// to use functions that have not yet been compiled. The potential
12429// problem of loading a function that has not yet been compiled can
12430// arise because we share code between contexts via the compilation
12431// cache.
12432THREADED_TEST(DictionaryICLoadedFunction) {
12433 v8::HandleScope scope;
12434 // Test LoadIC.
12435 for (int i = 0; i < 2; i++) {
12436 LocalContext context;
12437 context->Global()->Set(v8_str("tmp"), v8::True());
12438 context->Global()->Delete(v8_str("tmp"));
12439 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12440 }
12441 // Test CallIC.
12442 for (int i = 0; i < 2; i++) {
12443 LocalContext context;
12444 context->Global()->Set(v8_str("tmp"), v8::True());
12445 context->Global()->Delete(v8_str("tmp"));
12446 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12447 }
12448}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012449
12450
12451// Test that cross-context new calls use the context of the callee to
12452// create the new JavaScript object.
12453THREADED_TEST(CrossContextNew) {
12454 v8::HandleScope scope;
12455 v8::Persistent<Context> context0 = Context::New();
12456 v8::Persistent<Context> context1 = Context::New();
12457
12458 // Allow cross-domain access.
12459 Local<String> token = v8_str("<security token>");
12460 context0->SetSecurityToken(token);
12461 context1->SetSecurityToken(token);
12462
12463 // Set an 'x' property on the Object prototype and define a
12464 // constructor function in context0.
12465 context0->Enter();
12466 CompileRun("Object.prototype.x = 42; function C() {};");
12467 context0->Exit();
12468
12469 // Call the constructor function from context0 and check that the
12470 // result has the 'x' property.
12471 context1->Enter();
12472 context1->Global()->Set(v8_str("other"), context0->Global());
12473 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12474 CHECK(value->IsInt32());
12475 CHECK_EQ(42, value->Int32Value());
12476 context1->Exit();
12477
12478 // Dispose the contexts to allow them to be garbage collected.
12479 context0.Dispose();
12480 context1.Dispose();
12481}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012482
12483
12484class RegExpInterruptTest {
12485 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012486 RegExpInterruptTest() : block_(NULL) {}
12487 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012488 void RunTest() {
12489 block_ = i::OS::CreateSemaphore(0);
12490 gc_count_ = 0;
12491 gc_during_regexp_ = 0;
12492 regexp_success_ = false;
12493 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012494 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012495 gc_thread.Start();
12496 v8::Locker::StartPreemption(1);
12497
12498 LongRunningRegExp();
12499 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012500 v8::Unlocker unlock(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012501 gc_thread.Join();
12502 }
12503 v8::Locker::StopPreemption();
12504 CHECK(regexp_success_);
12505 CHECK(gc_success_);
12506 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012507
ager@chromium.org381abbb2009-02-25 13:23:22 +000012508 private:
12509 // Number of garbage collections required.
12510 static const int kRequiredGCs = 5;
12511
12512 class GCThread : public i::Thread {
12513 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012514 explicit GCThread(RegExpInterruptTest* test)
12515 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012516 virtual void Run() {
12517 test_->CollectGarbage();
12518 }
12519 private:
12520 RegExpInterruptTest* test_;
12521 };
12522
12523 void CollectGarbage() {
12524 block_->Wait();
12525 while (gc_during_regexp_ < kRequiredGCs) {
12526 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012527 v8::Locker lock(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012528 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012529 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012530 gc_count_++;
12531 }
12532 i::OS::Sleep(1);
12533 }
12534 gc_success_ = true;
12535 }
12536
12537 void LongRunningRegExp() {
12538 block_->Signal(); // Enable garbage collection thread on next preemption.
12539 int rounds = 0;
12540 while (gc_during_regexp_ < kRequiredGCs) {
12541 int gc_before = gc_count_;
12542 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012543 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012544 const char* c_source =
12545 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12546 ".exec('aaaaaaaaaaaaaaab') === null";
12547 Local<String> source = String::New(c_source);
12548 Local<Script> script = Script::Compile(source);
12549 Local<Value> result = script->Run();
12550 if (!result->BooleanValue()) {
12551 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12552 return;
12553 }
12554 }
12555 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012556 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012557 const char* c_source =
12558 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12559 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12560 Local<String> source = String::New(c_source);
12561 Local<Script> script = Script::Compile(source);
12562 Local<Value> result = script->Run();
12563 if (!result->BooleanValue()) {
12564 gc_during_regexp_ = kRequiredGCs;
12565 return;
12566 }
12567 }
12568 int gc_after = gc_count_;
12569 gc_during_regexp_ += gc_after - gc_before;
12570 rounds++;
12571 i::OS::Sleep(1);
12572 }
12573 regexp_success_ = true;
12574 }
12575
12576 i::Semaphore* block_;
12577 int gc_count_;
12578 int gc_during_regexp_;
12579 bool regexp_success_;
12580 bool gc_success_;
12581};
12582
12583
12584// Test that a regular expression execution can be interrupted and
12585// survive a garbage collection.
12586TEST(RegExpInterruption) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012587 v8::Locker lock(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012588 v8::V8::Initialize();
12589 v8::HandleScope scope;
12590 Local<Context> local_env;
12591 {
12592 LocalContext env;
12593 local_env = env.local();
12594 }
12595
12596 // Local context should still be live.
12597 CHECK(!local_env.IsEmpty());
12598 local_env->Enter();
12599
12600 // Should complete without problems.
12601 RegExpInterruptTest().RunTest();
12602
12603 local_env->Exit();
12604}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012605
12606
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012607class ApplyInterruptTest {
12608 public:
12609 ApplyInterruptTest() : block_(NULL) {}
12610 ~ApplyInterruptTest() { delete block_; }
12611 void RunTest() {
12612 block_ = i::OS::CreateSemaphore(0);
12613 gc_count_ = 0;
12614 gc_during_apply_ = 0;
12615 apply_success_ = false;
12616 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012617 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012618 gc_thread.Start();
12619 v8::Locker::StartPreemption(1);
12620
12621 LongRunningApply();
12622 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012623 v8::Unlocker unlock(CcTest::default_isolate());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012624 gc_thread.Join();
12625 }
12626 v8::Locker::StopPreemption();
12627 CHECK(apply_success_);
12628 CHECK(gc_success_);
12629 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012630
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012631 private:
12632 // Number of garbage collections required.
12633 static const int kRequiredGCs = 2;
12634
12635 class GCThread : public i::Thread {
12636 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012637 explicit GCThread(ApplyInterruptTest* test)
12638 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012639 virtual void Run() {
12640 test_->CollectGarbage();
12641 }
12642 private:
12643 ApplyInterruptTest* test_;
12644 };
12645
12646 void CollectGarbage() {
12647 block_->Wait();
12648 while (gc_during_apply_ < kRequiredGCs) {
12649 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012650 v8::Locker lock(CcTest::default_isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012651 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012652 gc_count_++;
12653 }
12654 i::OS::Sleep(1);
12655 }
12656 gc_success_ = true;
12657 }
12658
12659 void LongRunningApply() {
12660 block_->Signal();
12661 int rounds = 0;
12662 while (gc_during_apply_ < kRequiredGCs) {
12663 int gc_before = gc_count_;
12664 {
12665 const char* c_source =
12666 "function do_very_little(bar) {"
12667 " this.foo = bar;"
12668 "}"
12669 "for (var i = 0; i < 100000; i++) {"
12670 " do_very_little.apply(this, ['bar']);"
12671 "}";
12672 Local<String> source = String::New(c_source);
12673 Local<Script> script = Script::Compile(source);
12674 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000012675 // Check that no exception was thrown.
12676 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012677 }
12678 int gc_after = gc_count_;
12679 gc_during_apply_ += gc_after - gc_before;
12680 rounds++;
12681 }
12682 apply_success_ = true;
12683 }
12684
12685 i::Semaphore* block_;
12686 int gc_count_;
12687 int gc_during_apply_;
12688 bool apply_success_;
12689 bool gc_success_;
12690};
12691
12692
12693// Test that nothing bad happens if we get a preemption just when we were
12694// about to do an apply().
12695TEST(ApplyInterruption) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012696 v8::Locker lock(CcTest::default_isolate());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012697 v8::V8::Initialize();
12698 v8::HandleScope scope;
12699 Local<Context> local_env;
12700 {
12701 LocalContext env;
12702 local_env = env.local();
12703 }
12704
12705 // Local context should still be live.
12706 CHECK(!local_env.IsEmpty());
12707 local_env->Enter();
12708
12709 // Should complete without problems.
12710 ApplyInterruptTest().RunTest();
12711
12712 local_env->Exit();
12713}
12714
12715
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012716// Verify that we can clone an object
12717TEST(ObjectClone) {
12718 v8::HandleScope scope;
12719 LocalContext env;
12720
12721 const char* sample =
12722 "var rv = {};" \
12723 "rv.alpha = 'hello';" \
12724 "rv.beta = 123;" \
12725 "rv;";
12726
12727 // Create an object, verify basics.
12728 Local<Value> val = CompileRun(sample);
12729 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012730 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012731 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12732
12733 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12734 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12735 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12736
12737 // Clone it.
12738 Local<v8::Object> clone = obj->Clone();
12739 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12740 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12741 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12742
12743 // Set a property on the clone, verify each object.
12744 clone->Set(v8_str("beta"), v8::Integer::New(456));
12745 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12746 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12747}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012748
12749
ager@chromium.org5ec48922009-05-05 07:25:34 +000012750class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12751 public:
12752 explicit AsciiVectorResource(i::Vector<const char> vector)
12753 : data_(vector) {}
12754 virtual ~AsciiVectorResource() {}
12755 virtual size_t length() const { return data_.length(); }
12756 virtual const char* data() const { return data_.start(); }
12757 private:
12758 i::Vector<const char> data_;
12759};
12760
12761
12762class UC16VectorResource : public v8::String::ExternalStringResource {
12763 public:
12764 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12765 : data_(vector) {}
12766 virtual ~UC16VectorResource() {}
12767 virtual size_t length() const { return data_.length(); }
12768 virtual const i::uc16* data() const { return data_.start(); }
12769 private:
12770 i::Vector<const i::uc16> data_;
12771};
12772
12773
12774static void MorphAString(i::String* string,
12775 AsciiVectorResource* ascii_resource,
12776 UC16VectorResource* uc16_resource) {
12777 CHECK(i::StringShape(string).IsExternal());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000012778 if (string->IsOneByteRepresentation()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000012779 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012780 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012781 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012782 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012783 i::ExternalTwoByteString* morphed =
12784 i::ExternalTwoByteString::cast(string);
12785 morphed->set_resource(uc16_resource);
12786 } else {
12787 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012789 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012790 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012791 i::ExternalAsciiString* morphed =
12792 i::ExternalAsciiString::cast(string);
12793 morphed->set_resource(ascii_resource);
12794 }
12795}
12796
12797
12798// Test that we can still flatten a string if the components it is built up
12799// from have been turned into 16 bit strings in the mean time.
12800THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012801 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000012802 const char* c_string = "Now is the time for all good men"
12803 " to come to the aid of the party";
12804 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12805 {
12806 v8::HandleScope scope;
12807 LocalContext env;
12808 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012809 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012810 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012811 i::Vector<const uint16_t>(two_byte_string,
12812 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012813
12814 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012816 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012817 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012818
12819 env->Global()->Set(v8_str("lhs"), lhs);
12820 env->Global()->Set(v8_str("rhs"), rhs);
12821
12822 CompileRun(
12823 "var cons = lhs + rhs;"
12824 "var slice = lhs.substring(1, lhs.length - 1);"
12825 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12826
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012827#ifndef ENABLE_LATIN_1
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012828 CHECK(!lhs->MayContainNonAscii());
12829 CHECK(!rhs->MayContainNonAscii());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012830#endif
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012831
ager@chromium.org5ec48922009-05-05 07:25:34 +000012832 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12833 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12834
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012835 // This should UTF-8 without flattening, since everything is ASCII.
12836 Handle<String> cons = v8_compile("cons")->Run().As<String>();
12837 CHECK_EQ(128, cons->Utf8Length());
12838 int nchars = -1;
12839 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12840 CHECK_EQ(128, nchars);
12841 CHECK_EQ(0, strcmp(
12842 utf_buffer,
12843 "Now is the time for all good men to come to the aid of the party"
12844 "Now is the time for all good men to come to the aid of the party"));
12845
ager@chromium.org5ec48922009-05-05 07:25:34 +000012846 // Now do some stuff to make sure the strings are flattened, etc.
12847 CompileRun(
12848 "/[^a-z]/.test(cons);"
12849 "/[^a-z]/.test(slice);"
12850 "/[^a-z]/.test(slice_on_cons);");
12851 const char* expected_cons =
12852 "Now is the time for all good men to come to the aid of the party"
12853 "Now is the time for all good men to come to the aid of the party";
12854 const char* expected_slice =
12855 "ow is the time for all good men to come to the aid of the part";
12856 const char* expected_slice_on_cons =
12857 "ow is the time for all good men to come to the aid of the party"
12858 "Now is the time for all good men to come to the aid of the part";
12859 CHECK_EQ(String::New(expected_cons),
12860 env->Global()->Get(v8_str("cons")));
12861 CHECK_EQ(String::New(expected_slice),
12862 env->Global()->Get(v8_str("slice")));
12863 CHECK_EQ(String::New(expected_slice_on_cons),
12864 env->Global()->Get(v8_str("slice_on_cons")));
12865 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012866 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000012867}
12868
12869
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012870TEST(CompileExternalTwoByteSource) {
12871 v8::HandleScope scope;
12872 LocalContext context;
12873
12874 // This is a very short list of sources, which currently is to check for a
12875 // regression caused by r2703.
12876 const char* ascii_sources[] = {
12877 "0.5",
12878 "-0.5", // This mainly testes PushBack in the Scanner.
12879 "--0.5", // This mainly testes PushBack in the Scanner.
12880 NULL
12881 };
12882
12883 // Compile the sources as external two byte strings.
12884 for (int i = 0; ascii_sources[i] != NULL; i++) {
12885 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12886 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012887 i::Vector<const uint16_t>(two_byte_string,
12888 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012889 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12890 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012891 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012892 }
12893}
12894
12895
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012896class RegExpStringModificationTest {
12897 public:
12898 RegExpStringModificationTest()
12899 : block_(i::OS::CreateSemaphore(0)),
12900 morphs_(0),
12901 morphs_during_regexp_(0),
12902 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12903 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12904 ~RegExpStringModificationTest() { delete block_; }
12905 void RunTest() {
12906 regexp_success_ = false;
12907 morph_success_ = false;
12908
12909 // Initialize the contents of two_byte_content_ to be a uc16 representation
12910 // of "aaaaaaaaaaaaaab".
12911 for (int i = 0; i < 14; i++) {
12912 two_byte_content_[i] = 'a';
12913 }
12914 two_byte_content_[14] = 'b';
12915
12916 // Create the input string for the regexp - the one we are going to change
12917 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012918 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012919
12920 // Inject the input as a global variable.
12921 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012922 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012923 i::Isolate::Current()->native_context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012924 *input_name,
12925 *input_,
12926 NONE,
12927 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012928
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012929 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012930 morph_thread.Start();
12931 v8::Locker::StartPreemption(1);
12932 LongRunningRegExp();
12933 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012934 v8::Unlocker unlock(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012935 morph_thread.Join();
12936 }
12937 v8::Locker::StopPreemption();
12938 CHECK(regexp_success_);
12939 CHECK(morph_success_);
12940 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012941
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012942 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012943 // Number of string modifications required.
12944 static const int kRequiredModifications = 5;
12945 static const int kMaxModifications = 100;
12946
12947 class MorphThread : public i::Thread {
12948 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012949 explicit MorphThread(RegExpStringModificationTest* test)
12950 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012951 virtual void Run() {
12952 test_->MorphString();
12953 }
12954 private:
12955 RegExpStringModificationTest* test_;
12956 };
12957
12958 void MorphString() {
12959 block_->Wait();
12960 while (morphs_during_regexp_ < kRequiredModifications &&
12961 morphs_ < kMaxModifications) {
12962 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012963 v8::Locker lock(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012964 // Swap string between ascii and two-byte representation.
12965 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000012966 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012967 morphs_++;
12968 }
12969 i::OS::Sleep(1);
12970 }
12971 morph_success_ = true;
12972 }
12973
12974 void LongRunningRegExp() {
12975 block_->Signal(); // Enable morphing thread on next preemption.
12976 while (morphs_during_regexp_ < kRequiredModifications &&
12977 morphs_ < kMaxModifications) {
12978 int morphs_before = morphs_;
12979 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000012980 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012981 // Match 15-30 "a"'s against 14 and a "b".
12982 const char* c_source =
12983 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12984 ".exec(input) === null";
12985 Local<String> source = String::New(c_source);
12986 Local<Script> script = Script::Compile(source);
12987 Local<Value> result = script->Run();
12988 CHECK(result->IsTrue());
12989 }
12990 int morphs_after = morphs_;
12991 morphs_during_regexp_ += morphs_after - morphs_before;
12992 }
12993 regexp_success_ = true;
12994 }
12995
12996 i::uc16 two_byte_content_[15];
12997 i::Semaphore* block_;
12998 int morphs_;
12999 int morphs_during_regexp_;
13000 bool regexp_success_;
13001 bool morph_success_;
13002 i::Handle<i::String> input_;
13003 AsciiVectorResource ascii_resource_;
13004 UC16VectorResource uc16_resource_;
13005};
13006
13007
13008// Test that a regular expression execution can be interrupted and
13009// the string changed without failing.
13010TEST(RegExpStringModification) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000013011 v8::Locker lock(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013012 v8::V8::Initialize();
13013 v8::HandleScope scope;
13014 Local<Context> local_env;
13015 {
13016 LocalContext env;
13017 local_env = env.local();
13018 }
13019
13020 // Local context should still be live.
13021 CHECK(!local_env.IsEmpty());
13022 local_env->Enter();
13023
13024 // Should complete without problems.
13025 RegExpStringModificationTest().RunTest();
13026
13027 local_env->Exit();
13028}
13029
13030
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013031// Test that we cannot set a property on the global object if there
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013032// is a read-only property in the prototype chain.
13033TEST(ReadOnlyPropertyInGlobalProto) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013034 i::FLAG_es5_readonly = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013035 v8::HandleScope scope;
13036 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13037 LocalContext context(0, templ);
13038 v8::Handle<v8::Object> global = context->Global();
13039 v8::Handle<v8::Object> global_proto =
13040 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13041 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
13042 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
13043 // Check without 'eval' or 'with'.
13044 v8::Handle<v8::Value> res =
13045 CompileRun("function f() { x = 42; return x; }; f()");
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013046 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013047 // Check with 'eval'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013048 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13049 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013050 // Check with 'with'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013051 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13052 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013053}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013054
13055static int force_set_set_count = 0;
13056static int force_set_get_count = 0;
13057bool pass_on_get = false;
13058
13059static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
13060 const v8::AccessorInfo& info) {
13061 force_set_get_count++;
13062 if (pass_on_get) {
13063 return v8::Handle<v8::Value>();
13064 } else {
13065 return v8::Int32::New(3);
13066 }
13067}
13068
13069static void ForceSetSetter(v8::Local<v8::String> name,
13070 v8::Local<v8::Value> value,
13071 const v8::AccessorInfo& info) {
13072 force_set_set_count++;
13073}
13074
13075static v8::Handle<v8::Value> ForceSetInterceptSetter(
13076 v8::Local<v8::String> name,
13077 v8::Local<v8::Value> value,
13078 const v8::AccessorInfo& info) {
13079 force_set_set_count++;
13080 return v8::Undefined();
13081}
13082
13083TEST(ForceSet) {
13084 force_set_get_count = 0;
13085 force_set_set_count = 0;
13086 pass_on_get = false;
13087
13088 v8::HandleScope scope;
13089 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13090 v8::Handle<v8::String> access_property = v8::String::New("a");
13091 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13092 LocalContext context(NULL, templ);
13093 v8::Handle<v8::Object> global = context->Global();
13094
13095 // Ordinary properties
13096 v8::Handle<v8::String> simple_property = v8::String::New("p");
13097 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
13098 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13099 // This should fail because the property is read-only
13100 global->Set(simple_property, v8::Int32::New(5));
13101 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13102 // This should succeed even though the property is read-only
13103 global->ForceSet(simple_property, v8::Int32::New(6));
13104 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13105
13106 // Accessors
13107 CHECK_EQ(0, force_set_set_count);
13108 CHECK_EQ(0, force_set_get_count);
13109 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13110 // CHECK_EQ the property shouldn't override it, just call the setter
13111 // which in this case does nothing.
13112 global->Set(access_property, v8::Int32::New(7));
13113 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13114 CHECK_EQ(1, force_set_set_count);
13115 CHECK_EQ(2, force_set_get_count);
13116 // Forcing the property to be set should override the accessor without
13117 // calling it
13118 global->ForceSet(access_property, v8::Int32::New(8));
13119 CHECK_EQ(8, global->Get(access_property)->Int32Value());
13120 CHECK_EQ(1, force_set_set_count);
13121 CHECK_EQ(2, force_set_get_count);
13122}
13123
13124TEST(ForceSetWithInterceptor) {
13125 force_set_get_count = 0;
13126 force_set_set_count = 0;
13127 pass_on_get = false;
13128
13129 v8::HandleScope scope;
13130 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13131 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
13132 LocalContext context(NULL, templ);
13133 v8::Handle<v8::Object> global = context->Global();
13134
13135 v8::Handle<v8::String> some_property = v8::String::New("a");
13136 CHECK_EQ(0, force_set_set_count);
13137 CHECK_EQ(0, force_set_get_count);
13138 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13139 // Setting the property shouldn't override it, just call the setter
13140 // which in this case does nothing.
13141 global->Set(some_property, v8::Int32::New(7));
13142 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13143 CHECK_EQ(1, force_set_set_count);
13144 CHECK_EQ(2, force_set_get_count);
13145 // Getting the property when the interceptor returns an empty handle
13146 // should yield undefined, since the property isn't present on the
13147 // object itself yet.
13148 pass_on_get = true;
13149 CHECK(global->Get(some_property)->IsUndefined());
13150 CHECK_EQ(1, force_set_set_count);
13151 CHECK_EQ(3, force_set_get_count);
13152 // Forcing the property to be set should cause the value to be
13153 // set locally without calling the interceptor.
13154 global->ForceSet(some_property, v8::Int32::New(8));
13155 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13156 CHECK_EQ(1, force_set_set_count);
13157 CHECK_EQ(4, force_set_get_count);
13158 // Reenabling the interceptor should cause it to take precedence over
13159 // the property
13160 pass_on_get = false;
13161 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13162 CHECK_EQ(1, force_set_set_count);
13163 CHECK_EQ(5, force_set_get_count);
13164 // The interceptor should also work for other properties
13165 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
13166 CHECK_EQ(1, force_set_set_count);
13167 CHECK_EQ(6, force_set_get_count);
13168}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013169
13170
ager@chromium.orge2902be2009-06-08 12:21:35 +000013171THREADED_TEST(ForceDelete) {
13172 v8::HandleScope scope;
13173 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13174 LocalContext context(NULL, templ);
13175 v8::Handle<v8::Object> global = context->Global();
13176
13177 // Ordinary properties
13178 v8::Handle<v8::String> simple_property = v8::String::New("p");
13179 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
13180 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13181 // This should fail because the property is dont-delete.
13182 CHECK(!global->Delete(simple_property));
13183 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13184 // This should succeed even though the property is dont-delete.
13185 CHECK(global->ForceDelete(simple_property));
13186 CHECK(global->Get(simple_property)->IsUndefined());
13187}
13188
13189
13190static int force_delete_interceptor_count = 0;
13191static bool pass_on_delete = false;
13192
13193
13194static v8::Handle<v8::Boolean> ForceDeleteDeleter(
13195 v8::Local<v8::String> name,
13196 const v8::AccessorInfo& info) {
13197 force_delete_interceptor_count++;
13198 if (pass_on_delete) {
13199 return v8::Handle<v8::Boolean>();
13200 } else {
13201 return v8::True();
13202 }
13203}
13204
13205
13206THREADED_TEST(ForceDeleteWithInterceptor) {
13207 force_delete_interceptor_count = 0;
13208 pass_on_delete = false;
13209
13210 v8::HandleScope scope;
13211 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13212 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
13213 LocalContext context(NULL, templ);
13214 v8::Handle<v8::Object> global = context->Global();
13215
13216 v8::Handle<v8::String> some_property = v8::String::New("a");
13217 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
13218
13219 // Deleting a property should get intercepted and nothing should
13220 // happen.
13221 CHECK_EQ(0, force_delete_interceptor_count);
13222 CHECK(global->Delete(some_property));
13223 CHECK_EQ(1, force_delete_interceptor_count);
13224 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13225 // Deleting the property when the interceptor returns an empty
13226 // handle should not delete the property since it is DontDelete.
13227 pass_on_delete = true;
13228 CHECK(!global->Delete(some_property));
13229 CHECK_EQ(2, force_delete_interceptor_count);
13230 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13231 // Forcing the property to be deleted should delete the value
13232 // without calling the interceptor.
13233 CHECK(global->ForceDelete(some_property));
13234 CHECK(global->Get(some_property)->IsUndefined());
13235 CHECK_EQ(2, force_delete_interceptor_count);
13236}
13237
13238
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013239// Make sure that forcing a delete invalidates any IC stubs, so we
13240// don't read the hole value.
13241THREADED_TEST(ForceDeleteIC) {
13242 v8::HandleScope scope;
13243 LocalContext context;
13244 // Create a DontDelete variable on the global object.
13245 CompileRun("this.__proto__ = { foo: 'horse' };"
13246 "var foo = 'fish';"
13247 "function f() { return foo.length; }");
13248 // Initialize the IC for foo in f.
13249 CompileRun("for (var i = 0; i < 4; i++) f();");
13250 // Make sure the value of foo is correct before the deletion.
13251 CHECK_EQ(4, CompileRun("f()")->Int32Value());
13252 // Force the deletion of foo.
13253 CHECK(context->Global()->ForceDelete(v8_str("foo")));
13254 // Make sure the value for foo is read from the prototype, and that
13255 // we don't get in trouble with reading the deleted cell value
13256 // sentinel.
13257 CHECK_EQ(5, CompileRun("f()")->Int32Value());
13258}
13259
13260
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013261TEST(InlinedFunctionAcrossContexts) {
13262 i::FLAG_allow_natives_syntax = true;
13263 v8::HandleScope outer_scope;
13264 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
13265 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
13266 ctx1->Enter();
13267
13268 {
13269 v8::HandleScope inner_scope;
13270 CompileRun("var G = 42; function foo() { return G; }");
13271 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
13272 ctx2->Enter();
13273 ctx2->Global()->Set(v8_str("o"), foo);
13274 v8::Local<v8::Value> res = CompileRun(
13275 "function f() { return o(); }"
13276 "for (var i = 0; i < 10; ++i) f();"
13277 "%OptimizeFunctionOnNextCall(f);"
13278 "f();");
13279 CHECK_EQ(42, res->Int32Value());
13280 ctx2->Exit();
13281 v8::Handle<v8::String> G_property = v8::String::New("G");
13282 CHECK(ctx1->Global()->ForceDelete(G_property));
13283 ctx2->Enter();
13284 ExpectString(
13285 "(function() {"
13286 " try {"
13287 " return f();"
13288 " } catch(e) {"
13289 " return e.toString();"
13290 " }"
13291 " })()",
13292 "ReferenceError: G is not defined");
13293 ctx2->Exit();
13294 ctx1->Exit();
13295 ctx1.Dispose();
13296 }
13297 ctx2.Dispose();
13298}
13299
13300
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013301v8::Persistent<Context> calling_context0;
13302v8::Persistent<Context> calling_context1;
13303v8::Persistent<Context> calling_context2;
13304
13305
13306// Check that the call to the callback is initiated in
13307// calling_context2, the directly calling context is calling_context1
13308// and the callback itself is in calling_context0.
13309static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
13310 ApiTestFuzzer::Fuzz();
13311 CHECK(Context::GetCurrent() == calling_context0);
13312 CHECK(Context::GetCalling() == calling_context1);
13313 CHECK(Context::GetEntered() == calling_context2);
13314 return v8::Integer::New(42);
13315}
13316
13317
13318THREADED_TEST(GetCallingContext) {
13319 v8::HandleScope scope;
13320
13321 calling_context0 = Context::New();
13322 calling_context1 = Context::New();
13323 calling_context2 = Context::New();
13324
13325 // Allow cross-domain access.
13326 Local<String> token = v8_str("<security token>");
13327 calling_context0->SetSecurityToken(token);
13328 calling_context1->SetSecurityToken(token);
13329 calling_context2->SetSecurityToken(token);
13330
13331 // Create an object with a C++ callback in context0.
13332 calling_context0->Enter();
13333 Local<v8::FunctionTemplate> callback_templ =
13334 v8::FunctionTemplate::New(GetCallingContextCallback);
13335 calling_context0->Global()->Set(v8_str("callback"),
13336 callback_templ->GetFunction());
13337 calling_context0->Exit();
13338
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013339 // Expose context0 in context1 and set up a function that calls the
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013340 // callback function.
13341 calling_context1->Enter();
13342 calling_context1->Global()->Set(v8_str("context0"),
13343 calling_context0->Global());
13344 CompileRun("function f() { context0.callback() }");
13345 calling_context1->Exit();
13346
13347 // Expose context1 in context2 and call the callback function in
13348 // context0 indirectly through f in context1.
13349 calling_context2->Enter();
13350 calling_context2->Global()->Set(v8_str("context1"),
13351 calling_context1->Global());
13352 CompileRun("context1.f()");
13353 calling_context2->Exit();
13354
13355 // Dispose the contexts to allow them to be garbage collected.
13356 calling_context0.Dispose();
13357 calling_context1.Dispose();
13358 calling_context2.Dispose();
13359 calling_context0.Clear();
13360 calling_context1.Clear();
13361 calling_context2.Clear();
13362}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013363
13364
13365// Check that a variable declaration with no explicit initialization
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013366// value does shadow an existing property in the prototype chain.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013367THREADED_TEST(InitGlobalVarInProtoChain) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013368 i::FLAG_es52_globals = true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013369 v8::HandleScope scope;
13370 LocalContext context;
13371 // Introduce a variable in the prototype chain.
13372 CompileRun("__proto__.x = 42");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013373 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013374 CHECK(!result->IsUndefined());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013375 CHECK_EQ(43, result->Int32Value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013376}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013377
13378
13379// Regression test for issue 398.
13380// If a function is added to an object, creating a constant function
13381// field, and the result is cloned, replacing the constant function on the
13382// original should not affect the clone.
13383// See http://code.google.com/p/v8/issues/detail?id=398
13384THREADED_TEST(ReplaceConstantFunction) {
13385 v8::HandleScope scope;
13386 LocalContext context;
13387 v8::Handle<v8::Object> obj = v8::Object::New();
13388 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
13389 v8::Handle<v8::String> foo_string = v8::String::New("foo");
13390 obj->Set(foo_string, func_templ->GetFunction());
13391 v8::Handle<v8::Object> obj_clone = obj->Clone();
13392 obj_clone->Set(foo_string, v8::String::New("Hello"));
13393 CHECK(!obj->Get(foo_string)->IsUndefined());
13394}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013395
13396
13397// Regression test for http://crbug.com/16276.
13398THREADED_TEST(Regress16276) {
13399 v8::HandleScope scope;
13400 LocalContext context;
13401 // Force the IC in f to be a dictionary load IC.
13402 CompileRun("function f(obj) { return obj.x; }\n"
13403 "var obj = { x: { foo: 42 }, y: 87 };\n"
13404 "var x = obj.x;\n"
13405 "delete obj.y;\n"
13406 "for (var i = 0; i < 5; i++) f(obj);");
13407 // Detach the global object to make 'this' refer directly to the
13408 // global object (not the proxy), and make sure that the dictionary
13409 // load IC doesn't mess up loading directly from the global object.
13410 context->DetachGlobal();
13411 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13412}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013413
13414
13415THREADED_TEST(PixelArray) {
13416 v8::HandleScope scope;
13417 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013418 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013419 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013420 i::Handle<i::ExternalPixelArray> pixels =
13421 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013422 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013423 v8::kExternalPixelArray,
13424 pixel_data));
13425 // Force GC to trigger verification.
13426 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013427 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013428 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013429 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013430 // Force GC to trigger verification.
13431 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013432 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013433 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013434 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013435 }
13436
13437 v8::Handle<v8::Object> obj = v8::Object::New();
13438 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13439 // Set the elements to be the pixels.
13440 // jsobj->set_elements(*pixels);
13441 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013442 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013443 obj->Set(v8_str("field"), v8::Int32::New(1503));
13444 context->Global()->Set(v8_str("pixels"), obj);
13445 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13446 CHECK_EQ(1503, result->Int32Value());
13447 result = CompileRun("pixels[1]");
13448 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013449
13450 result = CompileRun("var sum = 0;"
13451 "for (var i = 0; i < 8; i++) {"
13452 " sum += pixels[i] = pixels[i] = -i;"
13453 "}"
13454 "sum;");
13455 CHECK_EQ(-28, result->Int32Value());
13456
13457 result = CompileRun("var sum = 0;"
13458 "for (var i = 0; i < 8; i++) {"
13459 " sum += pixels[i] = pixels[i] = 0;"
13460 "}"
13461 "sum;");
13462 CHECK_EQ(0, result->Int32Value());
13463
13464 result = CompileRun("var sum = 0;"
13465 "for (var i = 0; i < 8; i++) {"
13466 " sum += pixels[i] = pixels[i] = 255;"
13467 "}"
13468 "sum;");
13469 CHECK_EQ(8 * 255, result->Int32Value());
13470
13471 result = CompileRun("var sum = 0;"
13472 "for (var i = 0; i < 8; i++) {"
13473 " sum += pixels[i] = pixels[i] = 256 + i;"
13474 "}"
13475 "sum;");
13476 CHECK_EQ(2076, result->Int32Value());
13477
13478 result = CompileRun("var sum = 0;"
13479 "for (var i = 0; i < 8; i++) {"
13480 " sum += pixels[i] = pixels[i] = i;"
13481 "}"
13482 "sum;");
13483 CHECK_EQ(28, result->Int32Value());
13484
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013485 result = CompileRun("var sum = 0;"
13486 "for (var i = 0; i < 8; i++) {"
13487 " sum += pixels[i];"
13488 "}"
13489 "sum;");
13490 CHECK_EQ(28, result->Int32Value());
13491
13492 i::Handle<i::Smi> value(i::Smi::FromInt(2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013493 i::Handle<i::Object> no_failure;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013494 no_failure =
13495 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013496 ASSERT(!no_failure.is_null());
13497 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013498 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013499 *value.location() = i::Smi::FromInt(256);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013500 no_failure =
13501 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013502 ASSERT(!no_failure.is_null());
13503 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013504 CHECK_EQ(255,
13505 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013506 *value.location() = i::Smi::FromInt(-1);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013507 no_failure =
13508 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013509 ASSERT(!no_failure.is_null());
13510 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013511 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013512
13513 result = CompileRun("for (var i = 0; i < 8; i++) {"
13514 " pixels[i] = (i * 65) - 109;"
13515 "}"
13516 "pixels[1] + pixels[6];");
13517 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013518 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13519 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13520 CHECK_EQ(21,
13521 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13522 CHECK_EQ(86,
13523 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13524 CHECK_EQ(151,
13525 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13526 CHECK_EQ(216,
13527 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13528 CHECK_EQ(255,
13529 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13530 CHECK_EQ(255,
13531 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013532 result = CompileRun("var sum = 0;"
13533 "for (var i = 0; i < 8; i++) {"
13534 " sum += pixels[i];"
13535 "}"
13536 "sum;");
13537 CHECK_EQ(984, result->Int32Value());
13538
13539 result = CompileRun("for (var i = 0; i < 8; i++) {"
13540 " pixels[i] = (i * 1.1);"
13541 "}"
13542 "pixels[1] + pixels[6];");
13543 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013544 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13545 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13546 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13547 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13548 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13549 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13550 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13551 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013552
13553 result = CompileRun("for (var i = 0; i < 8; i++) {"
13554 " pixels[7] = undefined;"
13555 "}"
13556 "pixels[7];");
13557 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013558 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013559
13560 result = CompileRun("for (var i = 0; i < 8; i++) {"
13561 " pixels[6] = '2.3';"
13562 "}"
13563 "pixels[6];");
13564 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013565 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013566
13567 result = CompileRun("for (var i = 0; i < 8; i++) {"
13568 " pixels[5] = NaN;"
13569 "}"
13570 "pixels[5];");
13571 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013572 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013573
13574 result = CompileRun("for (var i = 0; i < 8; i++) {"
13575 " pixels[8] = Infinity;"
13576 "}"
13577 "pixels[8];");
13578 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013579 CHECK_EQ(255,
13580 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013581
13582 result = CompileRun("for (var i = 0; i < 8; i++) {"
13583 " pixels[9] = -Infinity;"
13584 "}"
13585 "pixels[9];");
13586 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013587 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013588
13589 result = CompileRun("pixels[3] = 33;"
13590 "delete pixels[3];"
13591 "pixels[3];");
13592 CHECK_EQ(33, result->Int32Value());
13593
13594 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13595 "pixels[2] = 12; pixels[3] = 13;"
13596 "pixels.__defineGetter__('2',"
13597 "function() { return 120; });"
13598 "pixels[2];");
13599 CHECK_EQ(12, result->Int32Value());
13600
13601 result = CompileRun("var js_array = new Array(40);"
13602 "js_array[0] = 77;"
13603 "js_array;");
13604 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13605
13606 result = CompileRun("pixels[1] = 23;"
13607 "pixels.__proto__ = [];"
13608 "js_array.__proto__ = pixels;"
13609 "js_array.concat(pixels);");
13610 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13611 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13612
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013613 result = CompileRun("pixels[1] = 23;");
13614 CHECK_EQ(23, result->Int32Value());
13615
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013616 // Test for index greater than 255. Regression test for:
13617 // http://code.google.com/p/chromium/issues/detail?id=26337.
13618 result = CompileRun("pixels[256] = 255;");
13619 CHECK_EQ(255, result->Int32Value());
13620 result = CompileRun("var i = 0;"
13621 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13622 "i");
13623 CHECK_EQ(255, result->Int32Value());
13624
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013625 // Make sure that pixel array ICs recognize when a non-pixel array
13626 // is passed to it.
13627 result = CompileRun("function pa_load(p) {"
13628 " var sum = 0;"
13629 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13630 " return sum;"
13631 "}"
13632 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13633 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13634 "just_ints = new Object();"
13635 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13636 "for (var i = 0; i < 10; ++i) {"
13637 " result = pa_load(just_ints);"
13638 "}"
13639 "result");
13640 CHECK_EQ(32640, result->Int32Value());
13641
13642 // Make sure that pixel array ICs recognize out-of-bound accesses.
13643 result = CompileRun("function pa_load(p, start) {"
13644 " var sum = 0;"
13645 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13646 " return sum;"
13647 "}"
13648 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13649 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13650 "for (var i = 0; i < 10; ++i) {"
13651 " result = pa_load(pixels,-10);"
13652 "}"
13653 "result");
13654 CHECK_EQ(0, result->Int32Value());
13655
13656 // Make sure that generic ICs properly handles a pixel array.
13657 result = CompileRun("function pa_load(p) {"
13658 " var sum = 0;"
13659 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13660 " return sum;"
13661 "}"
13662 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13663 "just_ints = new Object();"
13664 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13665 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13666 "for (var i = 0; i < 10; ++i) {"
13667 " result = pa_load(pixels);"
13668 "}"
13669 "result");
13670 CHECK_EQ(32640, result->Int32Value());
13671
13672 // Make sure that generic load ICs recognize out-of-bound accesses in
13673 // pixel arrays.
13674 result = CompileRun("function pa_load(p, start) {"
13675 " var sum = 0;"
13676 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13677 " return sum;"
13678 "}"
13679 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13680 "just_ints = new Object();"
13681 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13682 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13683 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13684 "for (var i = 0; i < 10; ++i) {"
13685 " result = pa_load(pixels,-10);"
13686 "}"
13687 "result");
13688 CHECK_EQ(0, result->Int32Value());
13689
13690 // Make sure that generic ICs properly handles other types than pixel
13691 // arrays (that the inlined fast pixel array test leaves the right information
13692 // in the right registers).
13693 result = CompileRun("function pa_load(p) {"
13694 " var sum = 0;"
13695 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13696 " return sum;"
13697 "}"
13698 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13699 "just_ints = new Object();"
13700 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13701 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13702 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13703 "sparse_array = new Object();"
13704 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13705 "sparse_array[1000000] = 3;"
13706 "for (var i = 0; i < 10; ++i) {"
13707 " result = pa_load(sparse_array);"
13708 "}"
13709 "result");
13710 CHECK_EQ(32640, result->Int32Value());
13711
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000013712 // Make sure that pixel array store ICs clamp values correctly.
13713 result = CompileRun("function pa_store(p) {"
13714 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13715 "}"
13716 "pa_store(pixels);"
13717 "var sum = 0;"
13718 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13719 "sum");
13720 CHECK_EQ(48896, result->Int32Value());
13721
13722 // Make sure that pixel array stores correctly handle accesses outside
13723 // of the pixel array..
13724 result = CompileRun("function pa_store(p,start) {"
13725 " for (var j = 0; j < 256; j++) {"
13726 " p[j+start] = j * 2;"
13727 " }"
13728 "}"
13729 "pa_store(pixels,0);"
13730 "pa_store(pixels,-128);"
13731 "var sum = 0;"
13732 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13733 "sum");
13734 CHECK_EQ(65280, result->Int32Value());
13735
13736 // Make sure that the generic store stub correctly handle accesses outside
13737 // of the pixel array..
13738 result = CompileRun("function pa_store(p,start) {"
13739 " for (var j = 0; j < 256; j++) {"
13740 " p[j+start] = j * 2;"
13741 " }"
13742 "}"
13743 "pa_store(pixels,0);"
13744 "just_ints = new Object();"
13745 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13746 "pa_store(just_ints, 0);"
13747 "pa_store(pixels,-128);"
13748 "var sum = 0;"
13749 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13750 "sum");
13751 CHECK_EQ(65280, result->Int32Value());
13752
13753 // Make sure that the generic keyed store stub clamps pixel array values
13754 // correctly.
13755 result = CompileRun("function pa_store(p) {"
13756 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13757 "}"
13758 "pa_store(pixels);"
13759 "just_ints = new Object();"
13760 "pa_store(just_ints);"
13761 "pa_store(pixels);"
13762 "var sum = 0;"
13763 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13764 "sum");
13765 CHECK_EQ(48896, result->Int32Value());
13766
13767 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013768 result = CompileRun("function pa_load(p) {"
13769 " var sum = 0;"
13770 " for (var i=0; i<256; ++i) {"
13771 " sum += p[i];"
13772 " }"
13773 " return sum; "
13774 "}"
13775 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013776 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013777 " result = pa_load(pixels);"
13778 "}"
13779 "result");
13780 CHECK_EQ(32640, result->Int32Value());
13781
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013782 // Make sure that pixel array stores are optimized by crankshaft.
13783 result = CompileRun("function pa_init(p) {"
13784 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13785 "}"
13786 "function pa_load(p) {"
13787 " var sum = 0;"
13788 " for (var i=0; i<256; ++i) {"
13789 " sum += p[i];"
13790 " }"
13791 " return sum; "
13792 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013793 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013794 " pa_init(pixels);"
13795 "}"
13796 "result = pa_load(pixels);"
13797 "result");
13798 CHECK_EQ(32640, result->Int32Value());
13799
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013800 free(pixel_data);
13801}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013802
ager@chromium.org96c75b52009-08-26 09:13:16 +000013803
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013804THREADED_TEST(PixelArrayInfo) {
13805 v8::HandleScope scope;
13806 LocalContext context;
13807 for (int size = 0; size < 100; size += 10) {
13808 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13809 v8::Handle<v8::Object> obj = v8::Object::New();
13810 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13811 CHECK(obj->HasIndexedPropertiesInPixelData());
13812 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13813 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13814 free(pixel_data);
13815 }
13816}
13817
13818
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013819static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13820 uint32_t index,
13821 const AccessorInfo& info) {
13822 ApiTestFuzzer::Fuzz();
13823 return v8::Handle<Value>();
13824}
13825
13826
13827static v8::Handle<Value> NotHandledIndexedPropertySetter(
13828 uint32_t index,
13829 Local<Value> value,
13830 const AccessorInfo& info) {
13831 ApiTestFuzzer::Fuzz();
13832 return v8::Handle<Value>();
13833}
13834
13835
13836THREADED_TEST(PixelArrayWithInterceptor) {
13837 v8::HandleScope scope;
13838 LocalContext context;
13839 const int kElementCount = 260;
13840 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013841 i::Handle<i::ExternalPixelArray> pixels =
13842 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013843 FACTORY->NewExternalArray(kElementCount,
13844 v8::kExternalPixelArray,
13845 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013846 for (int i = 0; i < kElementCount; i++) {
13847 pixels->set(i, i % 256);
13848 }
13849 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13850 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13851 NotHandledIndexedPropertySetter);
13852 v8::Handle<v8::Object> obj = templ->NewInstance();
13853 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13854 context->Global()->Set(v8_str("pixels"), obj);
13855 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13856 CHECK_EQ(1, result->Int32Value());
13857 result = CompileRun("var sum = 0;"
13858 "for (var i = 0; i < 8; i++) {"
13859 " sum += pixels[i] = pixels[i] = -i;"
13860 "}"
13861 "sum;");
13862 CHECK_EQ(-28, result->Int32Value());
13863 result = CompileRun("pixels.hasOwnProperty('1')");
13864 CHECK(result->BooleanValue());
13865 free(pixel_data);
13866}
13867
13868
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013869static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13870 switch (array_type) {
13871 case v8::kExternalByteArray:
13872 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013873 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013874 return 1;
13875 break;
13876 case v8::kExternalShortArray:
13877 case v8::kExternalUnsignedShortArray:
13878 return 2;
13879 break;
13880 case v8::kExternalIntArray:
13881 case v8::kExternalUnsignedIntArray:
13882 case v8::kExternalFloatArray:
13883 return 4;
13884 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013885 case v8::kExternalDoubleArray:
13886 return 8;
13887 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013888 default:
13889 UNREACHABLE();
13890 return -1;
13891 }
13892 UNREACHABLE();
13893 return -1;
13894}
13895
13896
ager@chromium.org3811b432009-10-28 14:53:37 +000013897template <class ExternalArrayClass, class ElementType>
13898static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13899 int64_t low,
13900 int64_t high) {
13901 v8::HandleScope scope;
13902 LocalContext context;
13903 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013904 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000013905 ElementType* array_data =
13906 static_cast<ElementType*>(malloc(kElementCount * element_size));
13907 i::Handle<ExternalArrayClass> array =
13908 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013909 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013910 // Force GC to trigger verification.
13911 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013912 for (int i = 0; i < kElementCount; i++) {
13913 array->set(i, static_cast<ElementType>(i));
13914 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013915 // Force GC to trigger verification.
13916 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013917 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013918 CHECK_EQ(static_cast<int64_t>(i),
13919 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000013920 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13921 }
13922
13923 v8::Handle<v8::Object> obj = v8::Object::New();
13924 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13925 // Set the elements to be the external array.
13926 obj->SetIndexedPropertiesToExternalArrayData(array_data,
13927 array_type,
13928 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013929 CHECK_EQ(
13930 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013931 obj->Set(v8_str("field"), v8::Int32::New(1503));
13932 context->Global()->Set(v8_str("ext_array"), obj);
13933 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13934 CHECK_EQ(1503, result->Int32Value());
13935 result = CompileRun("ext_array[1]");
13936 CHECK_EQ(1, result->Int32Value());
13937
13938 // Check pass through of assigned smis
13939 result = CompileRun("var sum = 0;"
13940 "for (var i = 0; i < 8; i++) {"
13941 " sum += ext_array[i] = ext_array[i] = -i;"
13942 "}"
13943 "sum;");
13944 CHECK_EQ(-28, result->Int32Value());
13945
13946 // Check assigned smis
13947 result = CompileRun("for (var i = 0; i < 8; i++) {"
13948 " ext_array[i] = i;"
13949 "}"
13950 "var sum = 0;"
13951 "for (var i = 0; i < 8; i++) {"
13952 " sum += ext_array[i];"
13953 "}"
13954 "sum;");
13955 CHECK_EQ(28, result->Int32Value());
13956
13957 // Check assigned smis in reverse order
13958 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13959 " ext_array[i] = i;"
13960 "}"
13961 "var sum = 0;"
13962 "for (var i = 0; i < 8; i++) {"
13963 " sum += ext_array[i];"
13964 "}"
13965 "sum;");
13966 CHECK_EQ(28, result->Int32Value());
13967
13968 // Check pass through of assigned HeapNumbers
13969 result = CompileRun("var sum = 0;"
13970 "for (var i = 0; i < 16; i+=2) {"
13971 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13972 "}"
13973 "sum;");
13974 CHECK_EQ(-28, result->Int32Value());
13975
13976 // Check assigned HeapNumbers
13977 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13978 " ext_array[i] = (i * 0.5);"
13979 "}"
13980 "var sum = 0;"
13981 "for (var i = 0; i < 16; i+=2) {"
13982 " sum += ext_array[i];"
13983 "}"
13984 "sum;");
13985 CHECK_EQ(28, result->Int32Value());
13986
13987 // Check assigned HeapNumbers in reverse order
13988 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13989 " ext_array[i] = (i * 0.5);"
13990 "}"
13991 "var sum = 0;"
13992 "for (var i = 0; i < 16; i+=2) {"
13993 " sum += ext_array[i];"
13994 "}"
13995 "sum;");
13996 CHECK_EQ(28, result->Int32Value());
13997
13998 i::ScopedVector<char> test_buf(1024);
13999
14000 // Check legal boundary conditions.
14001 // The repeated loads and stores ensure the ICs are exercised.
14002 const char* boundary_program =
14003 "var res = 0;"
14004 "for (var i = 0; i < 16; i++) {"
14005 " ext_array[i] = %lld;"
14006 " if (i > 8) {"
14007 " res = ext_array[i];"
14008 " }"
14009 "}"
14010 "res;";
14011 i::OS::SNPrintF(test_buf,
14012 boundary_program,
14013 low);
14014 result = CompileRun(test_buf.start());
14015 CHECK_EQ(low, result->IntegerValue());
14016
14017 i::OS::SNPrintF(test_buf,
14018 boundary_program,
14019 high);
14020 result = CompileRun(test_buf.start());
14021 CHECK_EQ(high, result->IntegerValue());
14022
14023 // Check misprediction of type in IC.
14024 result = CompileRun("var tmp_array = ext_array;"
14025 "var sum = 0;"
14026 "for (var i = 0; i < 8; i++) {"
14027 " tmp_array[i] = i;"
14028 " sum += tmp_array[i];"
14029 " if (i == 4) {"
14030 " tmp_array = {};"
14031 " }"
14032 "}"
14033 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014034 // Force GC to trigger verification.
14035 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000014036 CHECK_EQ(28, result->Int32Value());
14037
14038 // Make sure out-of-range loads do not throw.
14039 i::OS::SNPrintF(test_buf,
14040 "var caught_exception = false;"
14041 "try {"
14042 " ext_array[%d];"
14043 "} catch (e) {"
14044 " caught_exception = true;"
14045 "}"
14046 "caught_exception;",
14047 kElementCount);
14048 result = CompileRun(test_buf.start());
14049 CHECK_EQ(false, result->BooleanValue());
14050
14051 // Make sure out-of-range stores do not throw.
14052 i::OS::SNPrintF(test_buf,
14053 "var caught_exception = false;"
14054 "try {"
14055 " ext_array[%d] = 1;"
14056 "} catch (e) {"
14057 " caught_exception = true;"
14058 "}"
14059 "caught_exception;",
14060 kElementCount);
14061 result = CompileRun(test_buf.start());
14062 CHECK_EQ(false, result->BooleanValue());
14063
14064 // Check other boundary conditions, values and operations.
14065 result = CompileRun("for (var i = 0; i < 8; i++) {"
14066 " ext_array[7] = undefined;"
14067 "}"
14068 "ext_array[7];");
14069 CHECK_EQ(0, result->Int32Value());
yangguo@chromium.org56454712012-02-16 15:33:53 +000014070 if (array_type == v8::kExternalDoubleArray ||
14071 array_type == v8::kExternalFloatArray) {
14072 CHECK_EQ(
ulan@chromium.org812308e2012-02-29 15:58:45 +000014073 static_cast<int>(i::OS::nan_value()),
yangguo@chromium.org56454712012-02-16 15:33:53 +000014074 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
14075 } else {
14076 CHECK_EQ(0, static_cast<int>(
14077 jsobj->GetElement(7)->ToObjectChecked()->Number()));
14078 }
ager@chromium.org3811b432009-10-28 14:53:37 +000014079
14080 result = CompileRun("for (var i = 0; i < 8; i++) {"
14081 " ext_array[6] = '2.3';"
14082 "}"
14083 "ext_array[6];");
14084 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014085 CHECK_EQ(
14086 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000014087
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014088 if (array_type != v8::kExternalFloatArray &&
14089 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014090 // Though the specification doesn't state it, be explicit about
14091 // converting NaNs and +/-Infinity to zero.
14092 result = CompileRun("for (var i = 0; i < 8; i++) {"
14093 " ext_array[i] = 5;"
14094 "}"
14095 "for (var i = 0; i < 8; i++) {"
14096 " ext_array[i] = NaN;"
14097 "}"
14098 "ext_array[5];");
14099 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014100 CHECK_EQ(0,
14101 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000014102
14103 result = CompileRun("for (var i = 0; i < 8; i++) {"
14104 " ext_array[i] = 5;"
14105 "}"
14106 "for (var i = 0; i < 8; i++) {"
14107 " ext_array[i] = Infinity;"
14108 "}"
14109 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014110 int expected_value =
14111 (array_type == v8::kExternalPixelArray) ? 255 : 0;
14112 CHECK_EQ(expected_value, result->Int32Value());
14113 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000014114 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000014115
14116 result = CompileRun("for (var i = 0; i < 8; i++) {"
14117 " ext_array[i] = 5;"
14118 "}"
14119 "for (var i = 0; i < 8; i++) {"
14120 " ext_array[i] = -Infinity;"
14121 "}"
14122 "ext_array[5];");
14123 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014124 CHECK_EQ(0,
14125 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014126
14127 // Check truncation behavior of integral arrays.
14128 const char* unsigned_data =
14129 "var source_data = [0.6, 10.6];"
14130 "var expected_results = [0, 10];";
14131 const char* signed_data =
14132 "var source_data = [0.6, 10.6, -0.6, -10.6];"
14133 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014134 const char* pixel_data =
14135 "var source_data = [0.6, 10.6];"
14136 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014137 bool is_unsigned =
14138 (array_type == v8::kExternalUnsignedByteArray ||
14139 array_type == v8::kExternalUnsignedShortArray ||
14140 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014141 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014142
14143 i::OS::SNPrintF(test_buf,
14144 "%s"
14145 "var all_passed = true;"
14146 "for (var i = 0; i < source_data.length; i++) {"
14147 " for (var j = 0; j < 8; j++) {"
14148 " ext_array[j] = source_data[i];"
14149 " }"
14150 " all_passed = all_passed &&"
14151 " (ext_array[5] == expected_results[i]);"
14152 "}"
14153 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014154 (is_unsigned ?
14155 unsigned_data :
14156 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014157 result = CompileRun(test_buf.start());
14158 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000014159 }
14160
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000014161 for (int i = 0; i < kElementCount; i++) {
14162 array->set(i, static_cast<ElementType>(i));
14163 }
14164 // Test complex assignments
14165 result = CompileRun("function ee_op_test_complex_func(sum) {"
14166 " for (var i = 0; i < 40; ++i) {"
14167 " sum += (ext_array[i] += 1);"
14168 " sum += (ext_array[i] -= 1);"
14169 " } "
14170 " return sum;"
14171 "}"
14172 "sum=0;"
14173 "for (var i=0;i<10000;++i) {"
14174 " sum=ee_op_test_complex_func(sum);"
14175 "}"
14176 "sum;");
14177 CHECK_EQ(16000000, result->Int32Value());
14178
14179 // Test count operations
14180 result = CompileRun("function ee_op_test_count_func(sum) {"
14181 " for (var i = 0; i < 40; ++i) {"
14182 " sum += (++ext_array[i]);"
14183 " sum += (--ext_array[i]);"
14184 " } "
14185 " return sum;"
14186 "}"
14187 "sum=0;"
14188 "for (var i=0;i<10000;++i) {"
14189 " sum=ee_op_test_count_func(sum);"
14190 "}"
14191 "sum;");
14192 CHECK_EQ(16000000, result->Int32Value());
14193
ager@chromium.org3811b432009-10-28 14:53:37 +000014194 result = CompileRun("ext_array[3] = 33;"
14195 "delete ext_array[3];"
14196 "ext_array[3];");
14197 CHECK_EQ(33, result->Int32Value());
14198
14199 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14200 "ext_array[2] = 12; ext_array[3] = 13;"
14201 "ext_array.__defineGetter__('2',"
14202 "function() { return 120; });"
14203 "ext_array[2];");
14204 CHECK_EQ(12, result->Int32Value());
14205
14206 result = CompileRun("var js_array = new Array(40);"
14207 "js_array[0] = 77;"
14208 "js_array;");
14209 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14210
14211 result = CompileRun("ext_array[1] = 23;"
14212 "ext_array.__proto__ = [];"
14213 "js_array.__proto__ = ext_array;"
14214 "js_array.concat(ext_array);");
14215 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14216 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14217
14218 result = CompileRun("ext_array[1] = 23;");
14219 CHECK_EQ(23, result->Int32Value());
14220
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014221 // Test more complex manipulations which cause eax to contain values
14222 // that won't be completely overwritten by loads from the arrays.
14223 // This catches bugs in the instructions used for the KeyedLoadIC
14224 // for byte and word types.
14225 {
14226 const int kXSize = 300;
14227 const int kYSize = 300;
14228 const int kLargeElementCount = kXSize * kYSize * 4;
14229 ElementType* large_array_data =
14230 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014231 v8::Handle<v8::Object> large_obj = v8::Object::New();
14232 // Set the elements to be the external array.
14233 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14234 array_type,
14235 kLargeElementCount);
14236 context->Global()->Set(v8_str("large_array"), large_obj);
14237 // Initialize contents of a few rows.
14238 for (int x = 0; x < 300; x++) {
14239 int row = 0;
14240 int offset = row * 300 * 4;
14241 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14242 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14243 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14244 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14245 row = 150;
14246 offset = row * 300 * 4;
14247 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14248 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14249 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14250 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14251 row = 298;
14252 offset = row * 300 * 4;
14253 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14254 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14255 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14256 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14257 }
14258 // The goal of the code below is to make "offset" large enough
14259 // that the computation of the index (which goes into eax) has
14260 // high bits set which will not be overwritten by a byte or short
14261 // load.
14262 result = CompileRun("var failed = false;"
14263 "var offset = 0;"
14264 "for (var i = 0; i < 300; i++) {"
14265 " if (large_array[4 * i] != 127 ||"
14266 " large_array[4 * i + 1] != 0 ||"
14267 " large_array[4 * i + 2] != 0 ||"
14268 " large_array[4 * i + 3] != 127) {"
14269 " failed = true;"
14270 " }"
14271 "}"
14272 "offset = 150 * 300 * 4;"
14273 "for (var i = 0; i < 300; i++) {"
14274 " if (large_array[offset + 4 * i] != 127 ||"
14275 " large_array[offset + 4 * i + 1] != 0 ||"
14276 " large_array[offset + 4 * i + 2] != 0 ||"
14277 " large_array[offset + 4 * i + 3] != 127) {"
14278 " failed = true;"
14279 " }"
14280 "}"
14281 "offset = 298 * 300 * 4;"
14282 "for (var i = 0; i < 300; i++) {"
14283 " if (large_array[offset + 4 * i] != 127 ||"
14284 " large_array[offset + 4 * i + 1] != 0 ||"
14285 " large_array[offset + 4 * i + 2] != 0 ||"
14286 " large_array[offset + 4 * i + 3] != 127) {"
14287 " failed = true;"
14288 " }"
14289 "}"
14290 "!failed;");
14291 CHECK_EQ(true, result->BooleanValue());
14292 free(large_array_data);
14293 }
14294
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014295 // The "" property descriptor is overloaded to store information about
14296 // the external array. Ensure that setting and accessing the "" property
14297 // works (it should overwrite the information cached about the external
14298 // array in the DescriptorArray) in various situations.
14299 result = CompileRun("ext_array[''] = 23; ext_array['']");
14300 CHECK_EQ(23, result->Int32Value());
14301
14302 // Property "" set after the external array is associated with the object.
14303 {
14304 v8::Handle<v8::Object> obj2 = v8::Object::New();
14305 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
14306 obj2->Set(v8_str(""), v8::Int32::New(1503));
14307 // Set the elements to be the external array.
14308 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14309 array_type,
14310 kElementCount);
14311 context->Global()->Set(v8_str("ext_array"), obj2);
14312 result = CompileRun("ext_array['']");
14313 CHECK_EQ(1503, result->Int32Value());
14314 }
14315
14316 // Property "" set after the external array is associated with the object.
14317 {
14318 v8::Handle<v8::Object> obj2 = v8::Object::New();
14319 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14320 // Set the elements to be the external array.
14321 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14322 array_type,
14323 kElementCount);
14324 obj2->Set(v8_str(""), v8::Int32::New(1503));
14325 context->Global()->Set(v8_str("ext_array"), obj2);
14326 result = CompileRun("ext_array['']");
14327 CHECK_EQ(1503, result->Int32Value());
14328 }
14329
14330 // Should reuse the map from previous test.
14331 {
14332 v8::Handle<v8::Object> obj2 = v8::Object::New();
14333 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14334 // Set the elements to be the external array. Should re-use the map
14335 // from previous test.
14336 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14337 array_type,
14338 kElementCount);
14339 context->Global()->Set(v8_str("ext_array"), obj2);
14340 result = CompileRun("ext_array['']");
14341 }
14342
14343 // Property "" is a constant function that shouldn't not be interfered with
14344 // when an external array is set.
14345 {
14346 v8::Handle<v8::Object> obj2 = v8::Object::New();
14347 // Start
14348 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14349
14350 // Add a constant function to an object.
14351 context->Global()->Set(v8_str("ext_array"), obj2);
14352 result = CompileRun("ext_array[''] = function() {return 1503;};"
14353 "ext_array['']();");
14354
14355 // Add an external array transition to the same map that
14356 // has the constant transition.
14357 v8::Handle<v8::Object> obj3 = v8::Object::New();
14358 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14359 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14360 array_type,
14361 kElementCount);
14362 context->Global()->Set(v8_str("ext_array"), obj3);
14363 }
14364
14365 // If a external array transition is in the map, it should get clobbered
14366 // by a constant function.
14367 {
14368 // Add an external array transition.
14369 v8::Handle<v8::Object> obj3 = v8::Object::New();
14370 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14371 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14372 array_type,
14373 kElementCount);
14374
14375 // Add a constant function to the same map that just got an external array
14376 // transition.
14377 v8::Handle<v8::Object> obj2 = v8::Object::New();
14378 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14379 context->Global()->Set(v8_str("ext_array"), obj2);
14380 result = CompileRun("ext_array[''] = function() {return 1503;};"
14381 "ext_array['']();");
14382 }
14383
ager@chromium.org3811b432009-10-28 14:53:37 +000014384 free(array_data);
14385}
14386
14387
14388THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014389 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014390 v8::kExternalByteArray,
14391 -128,
14392 127);
14393}
14394
14395
14396THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014397 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014398 v8::kExternalUnsignedByteArray,
14399 0,
14400 255);
14401}
14402
14403
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014404THREADED_TEST(ExternalPixelArray) {
14405 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14406 v8::kExternalPixelArray,
14407 0,
14408 255);
14409}
14410
14411
ager@chromium.org3811b432009-10-28 14:53:37 +000014412THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014413 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014414 v8::kExternalShortArray,
14415 -32768,
14416 32767);
14417}
14418
14419
14420THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014421 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014422 v8::kExternalUnsignedShortArray,
14423 0,
14424 65535);
14425}
14426
14427
14428THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014429 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014430 v8::kExternalIntArray,
14431 INT_MIN, // -2147483648
14432 INT_MAX); // 2147483647
14433}
14434
14435
14436THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014437 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014438 v8::kExternalUnsignedIntArray,
14439 0,
14440 UINT_MAX); // 4294967295
14441}
14442
14443
14444THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014445 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014446 v8::kExternalFloatArray,
14447 -500,
14448 500);
14449}
14450
14451
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014452THREADED_TEST(ExternalDoubleArray) {
14453 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14454 v8::kExternalDoubleArray,
14455 -500,
14456 500);
14457}
14458
14459
ager@chromium.org3811b432009-10-28 14:53:37 +000014460THREADED_TEST(ExternalArrays) {
14461 TestExternalByteArray();
14462 TestExternalUnsignedByteArray();
14463 TestExternalShortArray();
14464 TestExternalUnsignedShortArray();
14465 TestExternalIntArray();
14466 TestExternalUnsignedIntArray();
14467 TestExternalFloatArray();
14468}
14469
14470
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014471void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14472 v8::HandleScope scope;
14473 LocalContext context;
14474 for (int size = 0; size < 100; size += 10) {
14475 int element_size = ExternalArrayElementSize(array_type);
14476 void* external_data = malloc(size * element_size);
14477 v8::Handle<v8::Object> obj = v8::Object::New();
14478 obj->SetIndexedPropertiesToExternalArrayData(
14479 external_data, array_type, size);
14480 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14481 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14482 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14483 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14484 free(external_data);
14485 }
14486}
14487
14488
14489THREADED_TEST(ExternalArrayInfo) {
14490 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
14491 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
14492 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
14493 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
14494 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
14495 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
14496 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014497 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014498 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014499}
14500
14501
danno@chromium.org412fa512012-09-14 13:28:26 +000014502void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
14503 v8::Handle<v8::Object> obj = v8::Object::New();
14504 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14505 last_location = last_message = NULL;
14506 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14507 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14508 CHECK_NE(NULL, last_location);
14509 CHECK_NE(NULL, last_message);
14510}
14511
14512
14513TEST(ExternalArrayLimits) {
14514 v8::HandleScope scope;
14515 LocalContext context;
14516 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
14517 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
14518 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
14519 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
14520 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
14521 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
14522 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
14523 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
14524 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
14525 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
14526 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
14527 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
14528 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
14529 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
14530 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
14531 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
14532 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
14533 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
14534}
14535
14536
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014537THREADED_TEST(ScriptContextDependence) {
14538 v8::HandleScope scope;
14539 LocalContext c1;
14540 const char *source = "foo";
14541 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
14542 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
14543 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14544 CHECK_EQ(dep->Run()->Int32Value(), 100);
14545 CHECK_EQ(indep->Run()->Int32Value(), 100);
14546 LocalContext c2;
14547 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14548 CHECK_EQ(dep->Run()->Int32Value(), 100);
14549 CHECK_EQ(indep->Run()->Int32Value(), 101);
14550}
14551
ager@chromium.org96c75b52009-08-26 09:13:16 +000014552
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014553THREADED_TEST(StackTrace) {
14554 v8::HandleScope scope;
14555 LocalContext context;
14556 v8::TryCatch try_catch;
14557 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14558 v8::Handle<v8::String> src = v8::String::New(source);
14559 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14560 v8::Script::New(src, origin)->Run();
14561 CHECK(try_catch.HasCaught());
14562 v8::String::Utf8Value stack(try_catch.StackTrace());
14563 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14564}
ager@chromium.org96c75b52009-08-26 09:13:16 +000014565
14566
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014567// Checks that a StackFrame has certain expected values.
14568void checkStackFrame(const char* expected_script_name,
14569 const char* expected_func_name, int expected_line_number,
14570 int expected_column, bool is_eval, bool is_constructor,
14571 v8::Handle<v8::StackFrame> frame) {
14572 v8::HandleScope scope;
14573 v8::String::Utf8Value func_name(frame->GetFunctionName());
14574 v8::String::Utf8Value script_name(frame->GetScriptName());
14575 if (*script_name == NULL) {
14576 // The situation where there is no associated script, like for evals.
14577 CHECK(expected_script_name == NULL);
14578 } else {
14579 CHECK(strstr(*script_name, expected_script_name) != NULL);
14580 }
14581 CHECK(strstr(*func_name, expected_func_name) != NULL);
14582 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14583 CHECK_EQ(expected_column, frame->GetColumn());
14584 CHECK_EQ(is_eval, frame->IsEval());
14585 CHECK_EQ(is_constructor, frame->IsConstructor());
14586}
14587
14588
14589v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
14590 v8::HandleScope scope;
14591 const char* origin = "capture-stack-trace-test";
14592 const int kOverviewTest = 1;
14593 const int kDetailedTest = 2;
14594
14595 ASSERT(args.Length() == 1);
14596
14597 int testGroup = args[0]->Int32Value();
14598 if (testGroup == kOverviewTest) {
14599 v8::Handle<v8::StackTrace> stackTrace =
14600 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
14601 CHECK_EQ(4, stackTrace->GetFrameCount());
14602 checkStackFrame(origin, "bar", 2, 10, false, false,
14603 stackTrace->GetFrame(0));
14604 checkStackFrame(origin, "foo", 6, 3, false, false,
14605 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014606 // This is the source string inside the eval which has the call to foo.
14607 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014608 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014609 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014610 checkStackFrame(origin, "", 8, 7, false, false,
14611 stackTrace->GetFrame(3));
14612
14613 CHECK(stackTrace->AsArray()->IsArray());
14614 } else if (testGroup == kDetailedTest) {
14615 v8::Handle<v8::StackTrace> stackTrace =
14616 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14617 CHECK_EQ(4, stackTrace->GetFrameCount());
14618 checkStackFrame(origin, "bat", 4, 22, false, false,
14619 stackTrace->GetFrame(0));
14620 checkStackFrame(origin, "baz", 8, 3, false, true,
14621 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014622#ifdef ENABLE_DEBUGGER_SUPPORT
14623 bool is_eval = true;
14624#else // ENABLE_DEBUGGER_SUPPORT
14625 bool is_eval = false;
14626#endif // ENABLE_DEBUGGER_SUPPORT
14627
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014628 // This is the source string inside the eval which has the call to baz.
14629 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014630 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014631 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014632 checkStackFrame(origin, "", 10, 1, false, false,
14633 stackTrace->GetFrame(3));
14634
14635 CHECK(stackTrace->AsArray()->IsArray());
14636 }
14637 return v8::Undefined();
14638}
14639
14640
14641// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014642// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14643// THREADED_TEST(CaptureStackTrace) {
14644TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014645 v8::HandleScope scope;
14646 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14647 Local<ObjectTemplate> templ = ObjectTemplate::New();
14648 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14649 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
14650 LocalContext context(0, templ);
14651
14652 // Test getting OVERVIEW information. Should ignore information that is not
14653 // script name, function name, line number, and column offset.
14654 const char *overview_source =
14655 "function bar() {\n"
14656 " var y; AnalyzeStackInNativeCode(1);\n"
14657 "}\n"
14658 "function foo() {\n"
14659 "\n"
14660 " bar();\n"
14661 "}\n"
14662 "var x;eval('new foo();');";
14663 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014664 v8::Handle<Value> overview_result(
14665 v8::Script::New(overview_src, origin)->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014666 CHECK(!overview_result.IsEmpty());
14667 CHECK(overview_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014668
14669 // Test getting DETAILED information.
14670 const char *detailed_source =
14671 "function bat() {AnalyzeStackInNativeCode(2);\n"
14672 "}\n"
14673 "\n"
14674 "function baz() {\n"
14675 " bat();\n"
14676 "}\n"
14677 "eval('new baz();');";
14678 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14679 // Make the script using a non-zero line and column offset.
14680 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14681 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14682 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14683 v8::Handle<v8::Script> detailed_script(
14684 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014685 v8::Handle<Value> detailed_result(detailed_script->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014686 CHECK(!detailed_result.IsEmpty());
14687 CHECK(detailed_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014688}
14689
14690
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014691static void StackTraceForUncaughtExceptionListener(
14692 v8::Handle<v8::Message> message,
14693 v8::Handle<Value>) {
14694 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14695 CHECK_EQ(2, stack_trace->GetFrameCount());
14696 checkStackFrame("origin", "foo", 2, 3, false, false,
14697 stack_trace->GetFrame(0));
14698 checkStackFrame("origin", "bar", 5, 3, false, false,
14699 stack_trace->GetFrame(1));
14700}
14701
14702TEST(CaptureStackTraceForUncaughtException) {
14703 report_count = 0;
14704 v8::HandleScope scope;
14705 LocalContext env;
14706 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14707 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14708
14709 Script::Compile(v8_str("function foo() {\n"
14710 " throw 1;\n"
14711 "};\n"
14712 "function bar() {\n"
14713 " foo();\n"
14714 "};"),
14715 v8_str("origin"))->Run();
14716 v8::Local<v8::Object> global = env->Global();
14717 Local<Value> trouble = global->Get(v8_str("bar"));
14718 CHECK(trouble->IsFunction());
14719 Function::Cast(*trouble)->Call(global, 0, NULL);
14720 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14721 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14722}
14723
14724
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014725TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14726 v8::HandleScope scope;
14727 LocalContext env;
14728 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14729 1024,
14730 v8::StackTrace::kDetailed);
14731
14732 CompileRun(
14733 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14734 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14735 " 'isConstructor'];\n"
14736 "for (var i = 0; i < setters.length; i++) {\n"
14737 " var prop = setters[i];\n"
14738 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14739 "}\n");
14740 CompileRun("throw 'exception';");
14741 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14742}
14743
14744
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014745static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14746 v8::Handle<v8::Value> data) {
14747 // Use the frame where JavaScript is called from.
14748 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14749 CHECK(!stack_trace.IsEmpty());
14750 int frame_count = stack_trace->GetFrameCount();
14751 CHECK_EQ(3, frame_count);
14752 int line_number[] = {1, 2, 5};
14753 for (int i = 0; i < frame_count; i++) {
14754 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14755 }
14756}
14757
14758
14759// Test that we only return the stack trace at the site where the exception
14760// is first thrown (not where it is rethrown).
14761TEST(RethrowStackTrace) {
14762 v8::HandleScope scope;
14763 LocalContext env;
14764 // We make sure that
14765 // - the stack trace of the ReferenceError in g() is reported.
14766 // - the stack trace is not overwritten when e1 is rethrown by t().
14767 // - the stack trace of e2 does not overwrite that of e1.
14768 const char* source =
14769 "function g() { error; } \n"
14770 "function f() { g(); } \n"
14771 "function t(e) { throw e; } \n"
14772 "try { \n"
14773 " f(); \n"
14774 "} catch (e1) { \n"
14775 " try { \n"
14776 " error; \n"
14777 " } catch (e2) { \n"
14778 " t(e1); \n"
14779 " } \n"
14780 "} \n";
14781 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14782 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14783 CompileRun(source);
14784 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14785 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14786}
14787
14788
14789static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14790 v8::Handle<v8::Value> data) {
14791 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14792 CHECK(!stack_trace.IsEmpty());
14793 int frame_count = stack_trace->GetFrameCount();
14794 CHECK_EQ(2, frame_count);
14795 int line_number[] = {3, 7};
14796 for (int i = 0; i < frame_count; i++) {
14797 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14798 }
14799}
14800
14801
14802// Test that we do not recognize identity for primitive exceptions.
14803TEST(RethrowPrimitiveStackTrace) {
14804 v8::HandleScope scope;
14805 LocalContext env;
14806 // We do not capture stack trace for non Error objects on creation time.
14807 // Instead, we capture the stack trace on last throw.
14808 const char* source =
14809 "function g() { throw 404; } \n"
14810 "function f() { g(); } \n"
14811 "function t(e) { throw e; } \n"
14812 "try { \n"
14813 " f(); \n"
14814 "} catch (e1) { \n"
14815 " t(e1) \n"
14816 "} \n";
14817 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14818 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14819 CompileRun(source);
14820 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14821 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14822}
14823
14824
14825static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14826 v8::Handle<v8::Value> data) {
14827 // Use the frame where JavaScript is called from.
14828 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14829 CHECK(!stack_trace.IsEmpty());
14830 CHECK_EQ(1, stack_trace->GetFrameCount());
14831 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14832}
14833
14834
14835// Test that the stack trace is captured when the error object is created and
14836// not where it is thrown.
14837TEST(RethrowExistingStackTrace) {
14838 v8::HandleScope scope;
14839 LocalContext env;
14840 const char* source =
14841 "var e = new Error(); \n"
14842 "throw e; \n";
14843 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14844 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14845 CompileRun(source);
14846 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14847 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14848}
14849
14850
14851static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14852 v8::Handle<v8::Value> data) {
14853 // Use the frame where JavaScript is called from.
14854 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14855 CHECK(!stack_trace.IsEmpty());
14856 CHECK_EQ(1, stack_trace->GetFrameCount());
14857 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14858}
14859
14860
14861// Test that the stack trace is captured where the bogus Error object is thrown.
14862TEST(RethrowBogusErrorStackTrace) {
14863 v8::HandleScope scope;
14864 LocalContext env;
14865 const char* source =
14866 "var e = {__proto__: new Error()} \n"
14867 "throw e; \n";
14868 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14869 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14870 CompileRun(source);
14871 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14872 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14873}
14874
14875
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014876v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
14877 v8::HandleScope scope;
14878 v8::Handle<v8::StackTrace> stackTrace =
14879 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14880 CHECK_EQ(5, stackTrace->GetFrameCount());
14881 v8::Handle<v8::String> url = v8_str("eval_url");
14882 for (int i = 0; i < 3; i++) {
14883 v8::Handle<v8::String> name =
14884 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14885 CHECK(!name.IsEmpty());
14886 CHECK_EQ(url, name);
14887 }
14888 return v8::Undefined();
14889}
14890
14891
14892TEST(SourceURLInStackTrace) {
14893 v8::HandleScope scope;
14894 Local<ObjectTemplate> templ = ObjectTemplate::New();
14895 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14896 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
14897 LocalContext context(0, templ);
14898
14899 const char *source =
14900 "function outer() {\n"
14901 "function bar() {\n"
14902 " AnalyzeStackOfEvalWithSourceURL();\n"
14903 "}\n"
14904 "function foo() {\n"
14905 "\n"
14906 " bar();\n"
14907 "}\n"
14908 "foo();\n"
14909 "}\n"
14910 "eval('(' + outer +')()//@ sourceURL=eval_url');";
14911 CHECK(CompileRun(source)->IsUndefined());
14912}
14913
14914
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000014915v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
14916 const v8::Arguments& args) {
14917 v8::HandleScope scope;
14918 v8::Handle<v8::StackTrace> stackTrace =
14919 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14920 CHECK_EQ(4, stackTrace->GetFrameCount());
14921 v8::Handle<v8::String> url = v8_str("url");
14922 for (int i = 0; i < 3; i++) {
14923 v8::Handle<v8::String> name =
14924 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14925 CHECK(!name.IsEmpty());
14926 CHECK_EQ(url, name);
14927 }
14928 return v8::Undefined();
14929}
14930
14931
14932TEST(InlineScriptWithSourceURLInStackTrace) {
14933 v8::HandleScope scope;
14934 Local<ObjectTemplate> templ = ObjectTemplate::New();
14935 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
14936 v8::FunctionTemplate::New(
14937 AnalyzeStackOfInlineScriptWithSourceURL));
14938 LocalContext context(0, templ);
14939
14940 const char *source =
14941 "function outer() {\n"
14942 "function bar() {\n"
14943 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
14944 "}\n"
14945 "function foo() {\n"
14946 "\n"
14947 " bar();\n"
14948 "}\n"
14949 "foo();\n"
14950 "}\n"
14951 "outer()\n"
14952 "//@ sourceURL=source_url";
14953 CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
14954}
14955
14956
14957v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
14958 const v8::Arguments& args) {
14959 v8::HandleScope scope;
14960 v8::Handle<v8::StackTrace> stackTrace =
14961 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14962 CHECK_EQ(4, stackTrace->GetFrameCount());
14963 v8::Handle<v8::String> url = v8_str("source_url");
14964 for (int i = 0; i < 3; i++) {
14965 v8::Handle<v8::String> name =
14966 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14967 CHECK(!name.IsEmpty());
14968 CHECK_EQ(url, name);
14969 }
14970 return v8::Undefined();
14971}
14972
14973
14974TEST(DynamicWithSourceURLInStackTrace) {
14975 v8::HandleScope scope;
14976 Local<ObjectTemplate> templ = ObjectTemplate::New();
14977 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
14978 v8::FunctionTemplate::New(
14979 AnalyzeStackOfDynamicScriptWithSourceURL));
14980 LocalContext context(0, templ);
14981
14982 const char *source =
14983 "function outer() {\n"
14984 "function bar() {\n"
14985 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14986 "}\n"
14987 "function foo() {\n"
14988 "\n"
14989 " bar();\n"
14990 "}\n"
14991 "foo();\n"
14992 "}\n"
14993 "outer()\n"
14994 "//@ sourceURL=source_url";
14995 CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
14996}
14997
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014998static void CreateGarbageInOldSpace() {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014999 v8::HandleScope scope;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015000 i::AlwaysAllocateScope always_allocate;
15001 for (int i = 0; i < 1000; i++) {
15002 FACTORY->NewFixedArray(1000, i::TENURED);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015003 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000015004}
15005
15006// Test that idle notification can be handled and eventually returns true.
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015007TEST(IdleNotification) {
15008 const intptr_t MB = 1024 * 1024;
15009 v8::HandleScope scope;
15010 LocalContext env;
15011 intptr_t initial_size = HEAP->SizeOfObjects();
15012 CreateGarbageInOldSpace();
15013 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15014 CHECK_GT(size_with_garbage, initial_size + MB);
15015 bool finished = false;
15016 for (int i = 0; i < 200 && !finished; i++) {
15017 finished = v8::V8::IdleNotification();
15018 }
15019 intptr_t final_size = HEAP->SizeOfObjects();
15020 CHECK(finished);
15021 CHECK_LT(final_size, initial_size + 1);
15022}
15023
15024
15025// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000015026TEST(IdleNotificationWithSmallHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015027 const intptr_t MB = 1024 * 1024;
15028 const int IdlePauseInMs = 900;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000015029 v8::HandleScope scope;
15030 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015031 intptr_t initial_size = HEAP->SizeOfObjects();
15032 CreateGarbageInOldSpace();
15033 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15034 CHECK_GT(size_with_garbage, initial_size + MB);
15035 bool finished = false;
15036 for (int i = 0; i < 200 && !finished; i++) {
15037 finished = v8::V8::IdleNotification(IdlePauseInMs);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015038 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015039 intptr_t final_size = HEAP->SizeOfObjects();
15040 CHECK(finished);
15041 CHECK_LT(final_size, initial_size + 1);
yangguo@chromium.org56454712012-02-16 15:33:53 +000015042}
15043
15044
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015045// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000015046TEST(IdleNotificationWithLargeHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015047 const intptr_t MB = 1024 * 1024;
15048 const int IdlePauseInMs = 900;
yangguo@chromium.org56454712012-02-16 15:33:53 +000015049 v8::HandleScope scope;
15050 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015051 intptr_t initial_size = HEAP->SizeOfObjects();
15052 CreateGarbageInOldSpace();
15053 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15054 CHECK_GT(size_with_garbage, initial_size + MB);
15055 bool finished = false;
15056 for (int i = 0; i < 200 && !finished; i++) {
15057 finished = v8::V8::IdleNotification(IdlePauseInMs);
yangguo@chromium.org56454712012-02-16 15:33:53 +000015058 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015059 intptr_t final_size = HEAP->SizeOfObjects();
15060 CHECK(finished);
15061 CHECK_LT(final_size, initial_size + 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015062}
15063
15064
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015065TEST(Regress2107) {
15066 const intptr_t MB = 1024 * 1024;
15067 const int kShortIdlePauseInMs = 100;
15068 const int kLongIdlePauseInMs = 1000;
15069 v8::HandleScope scope;
15070 LocalContext env;
15071 intptr_t initial_size = HEAP->SizeOfObjects();
15072 // Send idle notification to start a round of incremental GCs.
15073 v8::V8::IdleNotification(kShortIdlePauseInMs);
15074 // Emulate 7 page reloads.
15075 for (int i = 0; i < 7; i++) {
15076 v8::Persistent<v8::Context> ctx = v8::Context::New();
15077 ctx->Enter();
15078 CreateGarbageInOldSpace();
15079 ctx->Exit();
15080 ctx.Dispose();
15081 v8::V8::ContextDisposedNotification();
15082 v8::V8::IdleNotification(kLongIdlePauseInMs);
15083 }
15084 // Create garbage and check that idle notification still collects it.
15085 CreateGarbageInOldSpace();
15086 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15087 CHECK_GT(size_with_garbage, initial_size + MB);
15088 bool finished = false;
15089 for (int i = 0; i < 200 && !finished; i++) {
15090 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
15091 }
15092 intptr_t final_size = HEAP->SizeOfObjects();
15093 CHECK_LT(final_size, initial_size + 1);
15094}
15095
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015096static uint32_t* stack_limit;
15097
15098static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015099 stack_limit = reinterpret_cast<uint32_t*>(
15100 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015101 return v8::Undefined();
15102}
15103
15104
15105// Uses the address of a local variable to determine the stack top now.
15106// Given a size, returns an address that is that far from the current
15107// top of stack.
15108static uint32_t* ComputeStackLimit(uint32_t size) {
15109 uint32_t* answer = &size - (size / sizeof(size));
15110 // If the size is very large and the stack is very near the bottom of
15111 // memory then the calculation above may wrap around and give an address
15112 // that is above the (downwards-growing) stack. In that case we return
15113 // a very low address.
15114 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
15115 return answer;
15116}
15117
15118
15119TEST(SetResourceConstraints) {
15120 static const int K = 1024;
15121 uint32_t* set_limit = ComputeStackLimit(128 * K);
15122
15123 // Set stack limit.
15124 v8::ResourceConstraints constraints;
15125 constraints.set_stack_limit(set_limit);
15126 CHECK(v8::SetResourceConstraints(&constraints));
15127
15128 // Execute a script.
15129 v8::HandleScope scope;
15130 LocalContext env;
15131 Local<v8::FunctionTemplate> fun_templ =
15132 v8::FunctionTemplate::New(GetStackLimitCallback);
15133 Local<Function> fun = fun_templ->GetFunction();
15134 env->Global()->Set(v8_str("get_stack_limit"), fun);
15135 CompileRun("get_stack_limit();");
15136
15137 CHECK(stack_limit == set_limit);
15138}
15139
15140
15141TEST(SetResourceConstraintsInThread) {
15142 uint32_t* set_limit;
15143 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000015144 v8::Locker locker(CcTest::default_isolate());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015145 static const int K = 1024;
15146 set_limit = ComputeStackLimit(128 * K);
15147
15148 // Set stack limit.
15149 v8::ResourceConstraints constraints;
15150 constraints.set_stack_limit(set_limit);
15151 CHECK(v8::SetResourceConstraints(&constraints));
15152
15153 // Execute a script.
15154 v8::HandleScope scope;
15155 LocalContext env;
15156 Local<v8::FunctionTemplate> fun_templ =
15157 v8::FunctionTemplate::New(GetStackLimitCallback);
15158 Local<Function> fun = fun_templ->GetFunction();
15159 env->Global()->Set(v8_str("get_stack_limit"), fun);
15160 CompileRun("get_stack_limit();");
15161
15162 CHECK(stack_limit == set_limit);
15163 }
15164 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000015165 v8::Locker locker(CcTest::default_isolate());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015166 CHECK(stack_limit == set_limit);
15167 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000015168}
ager@chromium.org3811b432009-10-28 14:53:37 +000015169
15170
15171THREADED_TEST(GetHeapStatistics) {
15172 v8::HandleScope scope;
15173 LocalContext c1;
15174 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015175 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
15176 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015177 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015178 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15179 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015180}
15181
15182
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015183class VisitorImpl : public v8::ExternalResourceVisitor {
15184 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015185 explicit VisitorImpl(TestResource** resource) {
15186 for (int i = 0; i < 4; i++) {
15187 resource_[i] = resource[i];
15188 found_resource_[i] = false;
15189 }
15190 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015191 virtual ~VisitorImpl() {}
15192 virtual void VisitExternalString(v8::Handle<v8::String> string) {
15193 if (!string->IsExternal()) {
15194 CHECK(string->IsExternalAscii());
15195 return;
15196 }
15197 v8::String::ExternalStringResource* resource =
15198 string->GetExternalStringResource();
15199 CHECK(resource);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015200 for (int i = 0; i < 4; i++) {
15201 if (resource_[i] == resource) {
15202 CHECK(!found_resource_[i]);
15203 found_resource_[i] = true;
15204 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015205 }
15206 }
15207 void CheckVisitedResources() {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015208 for (int i = 0; i < 4; i++) {
15209 CHECK(found_resource_[i]);
15210 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015211 }
15212
15213 private:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015214 v8::String::ExternalStringResource* resource_[4];
15215 bool found_resource_[4];
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015216};
15217
15218TEST(VisitExternalStrings) {
15219 v8::HandleScope scope;
15220 LocalContext env;
15221 const char* string = "Some string";
15222 uint16_t* two_byte_string = AsciiToTwoByteString(string);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015223 TestResource* resource[4];
15224 resource[0] = new TestResource(two_byte_string);
15225 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
15226 resource[1] = new TestResource(two_byte_string);
15227 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015228
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015229 // Externalized symbol.
15230 resource[2] = new TestResource(two_byte_string);
15231 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
15232 CHECK(string2->MakeExternal(resource[2]));
15233
15234 // Symbolized External.
15235 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15236 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
15237 HEAP->CollectAllAvailableGarbage(); // Tenure string.
15238 // Turn into a symbol.
15239 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
15240 CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure());
15241 CHECK(string3_i->IsSymbol());
15242
15243 // We need to add usages for string* to avoid warnings in GCC 4.7
15244 CHECK(string0->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015245 CHECK(string1->IsExternal());
15246 CHECK(string2->IsExternal());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015247 CHECK(string3->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015248
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015249 VisitorImpl visitor(resource);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015250 v8::V8::VisitExternalResources(&visitor);
15251 visitor.CheckVisitedResources();
15252}
15253
15254
ager@chromium.org3811b432009-10-28 14:53:37 +000015255static double DoubleFromBits(uint64_t value) {
15256 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015257 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015258 return target;
15259}
15260
15261
15262static uint64_t DoubleToBits(double value) {
15263 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015264 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015265 return target;
15266}
15267
15268
15269static double DoubleToDateTime(double input) {
15270 double date_limit = 864e13;
15271 if (IsNaN(input) || input < -date_limit || input > date_limit) {
15272 return i::OS::nan_value();
15273 }
15274 return (input < 0) ? -(floor(-input)) : floor(input);
15275}
15276
15277// We don't have a consistent way to write 64-bit constants syntactically, so we
15278// split them into two 32-bit constants and combine them programmatically.
15279static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15280 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15281}
15282
15283
15284THREADED_TEST(QuietSignalingNaNs) {
15285 v8::HandleScope scope;
15286 LocalContext context;
15287 v8::TryCatch try_catch;
15288
15289 // Special double values.
15290 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15291 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15292 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15293 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15294 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15295 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15296 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15297
15298 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15299 // on either side of the epoch.
15300 double date_limit = 864e13;
15301
15302 double test_values[] = {
15303 snan,
15304 qnan,
15305 infinity,
15306 max_normal,
15307 date_limit + 1,
15308 date_limit,
15309 min_normal,
15310 max_denormal,
15311 min_denormal,
15312 0,
15313 -0,
15314 -min_denormal,
15315 -max_denormal,
15316 -min_normal,
15317 -date_limit,
15318 -date_limit - 1,
15319 -max_normal,
15320 -infinity,
15321 -qnan,
15322 -snan
15323 };
15324 int num_test_values = 20;
15325
15326 for (int i = 0; i < num_test_values; i++) {
15327 double test_value = test_values[i];
15328
15329 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15330 v8::Handle<v8::Value> number = v8::Number::New(test_value);
15331 double stored_number = number->NumberValue();
15332 if (!IsNaN(test_value)) {
15333 CHECK_EQ(test_value, stored_number);
15334 } else {
15335 uint64_t stored_bits = DoubleToBits(stored_number);
15336 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015337#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15338 // Most significant fraction bit for quiet nan is set to 0
15339 // on MIPS architecture. Allowed by IEEE-754.
15340 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15341#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015342 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015343#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015344 }
15345
15346 // Check that Date::New preserves non-NaNs in the date range and
15347 // quiets SNaNs.
15348 v8::Handle<v8::Value> date = v8::Date::New(test_value);
15349 double expected_stored_date = DoubleToDateTime(test_value);
15350 double stored_date = date->NumberValue();
15351 if (!IsNaN(expected_stored_date)) {
15352 CHECK_EQ(expected_stored_date, stored_date);
15353 } else {
15354 uint64_t stored_bits = DoubleToBits(stored_date);
15355 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015356#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15357 // Most significant fraction bit for quiet nan is set to 0
15358 // on MIPS architecture. Allowed by IEEE-754.
15359 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15360#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015361 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015362#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015363 }
15364 }
15365}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015366
15367
15368static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
15369 v8::HandleScope scope;
15370 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015371 v8::Handle<v8::String> str(args[0]->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015372 USE(str);
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015373 if (tc.HasCaught())
15374 return tc.ReThrow();
15375 return v8::Undefined();
15376}
15377
15378
15379// Test that an exception can be propagated down through a spaghetti
15380// stack using ReThrow.
15381THREADED_TEST(SpaghettiStackReThrow) {
15382 v8::HandleScope scope;
15383 LocalContext context;
15384 context->Global()->Set(
15385 v8::String::New("s"),
15386 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15387 v8::TryCatch try_catch;
15388 CompileRun(
15389 "var i = 0;"
15390 "var o = {"
15391 " toString: function () {"
15392 " if (i == 10) {"
15393 " throw 'Hey!';"
15394 " } else {"
15395 " i++;"
15396 " return s(o);"
15397 " }"
15398 " }"
15399 "};"
15400 "s(o);");
15401 CHECK(try_catch.HasCaught());
15402 v8::String::Utf8Value value(try_catch.Exception());
15403 CHECK_EQ(0, strcmp(*value, "Hey!"));
15404}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015405
15406
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015407TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015408 v8::V8::Initialize();
15409
15410 v8::HandleScope scope;
15411 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000015412 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015413 int gc_count;
15414
ager@chromium.org60121232009-12-03 11:25:37 +000015415 // Create a context used to keep the code from aging in the compilation
15416 // cache.
15417 other_context = Context::New();
15418
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015419 // Context-dependent context data creates reference from the compilation
15420 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015421 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015422 context = Context::New();
15423 {
15424 v8::HandleScope scope;
15425
15426 context->Enter();
15427 Local<v8::String> obj = v8::String::New("");
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000015428 context->SetEmbedderData(0, obj);
ager@chromium.org60121232009-12-03 11:25:37 +000015429 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015430 context->Exit();
15431 }
15432 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015433 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015434 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015435 other_context->Enter();
15436 CompileRun(source_simple);
15437 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015438 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015439 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015440 }
ager@chromium.org60121232009-12-03 11:25:37 +000015441 CHECK_GE(2, gc_count);
15442 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015443
15444 // Eval in a function creates reference from the compilation cache to the
15445 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015446 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015447 context = Context::New();
15448 {
15449 v8::HandleScope scope;
15450
15451 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000015452 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015453 context->Exit();
15454 }
15455 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015456 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015457 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015458 other_context->Enter();
15459 CompileRun(source_eval);
15460 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015461 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015462 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015463 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000015464 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015465 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015466
15467 // Looking up the line number for an exception creates reference from the
15468 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015469 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015470 context = Context::New();
15471 {
15472 v8::HandleScope scope;
15473
15474 context->Enter();
15475 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000015476 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015477 CHECK(try_catch.HasCaught());
15478 v8::Handle<v8::Message> message = try_catch.Message();
15479 CHECK(!message.IsEmpty());
15480 CHECK_EQ(1, message->GetLineNumber());
15481 context->Exit();
15482 }
15483 context.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000015484 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015485 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015486 other_context->Enter();
15487 CompileRun(source_exception);
15488 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015489 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015490 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015491 }
ager@chromium.org60121232009-12-03 11:25:37 +000015492 CHECK_GE(2, gc_count);
15493 CHECK_EQ(1, GetGlobalObjectsCount());
15494
15495 other_context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015496 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015497}
ager@chromium.org5c838252010-02-19 08:53:10 +000015498
15499
15500THREADED_TEST(ScriptOrigin) {
15501 v8::HandleScope scope;
15502 LocalContext env;
15503 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15504 v8::Handle<v8::String> script = v8::String::New(
15505 "function f() {}\n\nfunction g() {}");
15506 v8::Script::Compile(script, &origin)->Run();
15507 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15508 env->Global()->Get(v8::String::New("f")));
15509 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15510 env->Global()->Get(v8::String::New("g")));
15511
15512 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15513 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15514 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15515
15516 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15517 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15518 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15519}
15520
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015521THREADED_TEST(FunctionGetInferredName) {
15522 v8::HandleScope scope;
15523 LocalContext env;
15524 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15525 v8::Handle<v8::String> script = v8::String::New(
15526 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15527 v8::Script::Compile(script, &origin)->Run();
15528 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15529 env->Global()->Get(v8::String::New("f")));
15530 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15531}
ager@chromium.org5c838252010-02-19 08:53:10 +000015532
15533THREADED_TEST(ScriptLineNumber) {
15534 v8::HandleScope scope;
15535 LocalContext env;
15536 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15537 v8::Handle<v8::String> script = v8::String::New(
15538 "function f() {}\n\nfunction g() {}");
15539 v8::Script::Compile(script, &origin)->Run();
15540 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15541 env->Global()->Get(v8::String::New("f")));
15542 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15543 env->Global()->Get(v8::String::New("g")));
15544 CHECK_EQ(0, f->GetScriptLineNumber());
15545 CHECK_EQ(2, g->GetScriptLineNumber());
15546}
15547
15548
danno@chromium.orgc612e022011-11-10 11:38:15 +000015549THREADED_TEST(ScriptColumnNumber) {
15550 v8::HandleScope scope;
15551 LocalContext env;
15552 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15553 v8::Integer::New(3), v8::Integer::New(2));
15554 v8::Handle<v8::String> script = v8::String::New(
15555 "function foo() {}\n\n function bar() {}");
15556 v8::Script::Compile(script, &origin)->Run();
15557 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15558 env->Global()->Get(v8::String::New("foo")));
15559 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15560 env->Global()->Get(v8::String::New("bar")));
15561 CHECK_EQ(14, foo->GetScriptColumnNumber());
15562 CHECK_EQ(17, bar->GetScriptColumnNumber());
15563}
15564
15565
15566THREADED_TEST(FunctionGetScriptId) {
15567 v8::HandleScope scope;
15568 LocalContext env;
15569 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15570 v8::Integer::New(3), v8::Integer::New(2));
15571 v8::Handle<v8::String> scriptSource = v8::String::New(
15572 "function foo() {}\n\n function bar() {}");
15573 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15574 script->Run();
15575 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15576 env->Global()->Get(v8::String::New("foo")));
15577 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15578 env->Global()->Get(v8::String::New("bar")));
15579 CHECK_EQ(script->Id(), foo->GetScriptId());
15580 CHECK_EQ(script->Id(), bar->GetScriptId());
15581}
15582
15583
ager@chromium.org5c838252010-02-19 08:53:10 +000015584static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15585 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015586 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15587 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015588 return v8_num(42);
15589}
15590
15591
15592static void SetterWhichSetsYOnThisTo23(Local<String> name,
15593 Local<Value> value,
15594 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015595 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15596 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015597 info.This()->Set(v8_str("y"), v8_num(23));
15598}
15599
15600
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015601Handle<Value> FooGetInterceptor(Local<String> name,
15602 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015603 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15604 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015605 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15606 return v8_num(42);
15607}
15608
15609
15610Handle<Value> FooSetInterceptor(Local<String> name,
15611 Local<Value> value,
15612 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015613 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15614 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015615 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15616 info.This()->Set(v8_str("y"), v8_num(23));
15617 return v8_num(23);
15618}
15619
15620
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015621TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000015622 v8::HandleScope scope;
15623 Local<ObjectTemplate> templ = ObjectTemplate::New();
15624 templ->SetAccessor(v8_str("x"),
15625 GetterWhichReturns42,
15626 SetterWhichSetsYOnThisTo23);
15627 LocalContext context;
15628 context->Global()->Set(v8_str("P"), templ->NewInstance());
15629 CompileRun("function C1() {"
15630 " this.x = 23;"
15631 "};"
15632 "C1.prototype = P;"
15633 "function C2() {"
15634 " this.x = 23"
15635 "};"
15636 "C2.prototype = { };"
15637 "C2.prototype.__proto__ = P;");
15638
15639 v8::Local<v8::Script> script;
15640 script = v8::Script::Compile(v8_str("new C1();"));
15641 for (int i = 0; i < 10; i++) {
15642 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15643 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15644 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15645 }
15646
15647 script = v8::Script::Compile(v8_str("new C2();"));
15648 for (int i = 0; i < 10; i++) {
15649 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15650 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15651 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15652 }
15653}
15654
15655
15656static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15657 Local<String> name, const AccessorInfo& info) {
15658 return v8_num(42);
15659}
15660
15661
15662static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15663 Local<String> name, Local<Value> value, const AccessorInfo& info) {
15664 if (name->Equals(v8_str("x"))) {
15665 info.This()->Set(v8_str("y"), v8_num(23));
15666 }
15667 return v8::Handle<Value>();
15668}
15669
15670
15671THREADED_TEST(InterceptorOnConstructorPrototype) {
15672 v8::HandleScope scope;
15673 Local<ObjectTemplate> templ = ObjectTemplate::New();
15674 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15675 NamedPropertySetterWhichSetsYOnThisTo23);
15676 LocalContext context;
15677 context->Global()->Set(v8_str("P"), templ->NewInstance());
15678 CompileRun("function C1() {"
15679 " this.x = 23;"
15680 "};"
15681 "C1.prototype = P;"
15682 "function C2() {"
15683 " this.x = 23"
15684 "};"
15685 "C2.prototype = { };"
15686 "C2.prototype.__proto__ = P;");
15687
15688 v8::Local<v8::Script> script;
15689 script = v8::Script::Compile(v8_str("new C1();"));
15690 for (int i = 0; i < 10; i++) {
15691 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15692 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15693 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15694 }
15695
15696 script = v8::Script::Compile(v8_str("new C2();"));
15697 for (int i = 0; i < 10; i++) {
15698 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15699 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15700 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15701 }
15702}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015703
15704
15705TEST(Bug618) {
15706 const char* source = "function C1() {"
15707 " this.x = 23;"
15708 "};"
15709 "C1.prototype = P;";
15710
15711 v8::HandleScope scope;
15712 LocalContext context;
15713 v8::Local<v8::Script> script;
15714
15715 // Use a simple object as prototype.
15716 v8::Local<v8::Object> prototype = v8::Object::New();
15717 prototype->Set(v8_str("y"), v8_num(42));
15718 context->Global()->Set(v8_str("P"), prototype);
15719
15720 // This compile will add the code to the compilation cache.
15721 CompileRun(source);
15722
15723 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000015724 // Allow enough iterations for the inobject slack tracking logic
15725 // to finalize instance size and install the fast construct stub.
15726 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015727 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15728 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15729 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15730 }
15731
15732 // Use an API object with accessors as prototype.
15733 Local<ObjectTemplate> templ = ObjectTemplate::New();
15734 templ->SetAccessor(v8_str("x"),
15735 GetterWhichReturns42,
15736 SetterWhichSetsYOnThisTo23);
15737 context->Global()->Set(v8_str("P"), templ->NewInstance());
15738
15739 // This compile will get the code from the compilation cache.
15740 CompileRun(source);
15741
15742 script = v8::Script::Compile(v8_str("new C1();"));
15743 for (int i = 0; i < 10; i++) {
15744 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15745 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15746 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15747 }
15748}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015749
15750int prologue_call_count = 0;
15751int epilogue_call_count = 0;
15752int prologue_call_count_second = 0;
15753int epilogue_call_count_second = 0;
15754
15755void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15756 ++prologue_call_count;
15757}
15758
15759void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15760 ++epilogue_call_count;
15761}
15762
15763void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15764 ++prologue_call_count_second;
15765}
15766
15767void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15768 ++epilogue_call_count_second;
15769}
15770
15771TEST(GCCallbacks) {
15772 LocalContext context;
15773
15774 v8::V8::AddGCPrologueCallback(PrologueCallback);
15775 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
15776 CHECK_EQ(0, prologue_call_count);
15777 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015778 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015779 CHECK_EQ(1, prologue_call_count);
15780 CHECK_EQ(1, epilogue_call_count);
15781 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
15782 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015783 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015784 CHECK_EQ(2, prologue_call_count);
15785 CHECK_EQ(2, epilogue_call_count);
15786 CHECK_EQ(1, prologue_call_count_second);
15787 CHECK_EQ(1, epilogue_call_count_second);
15788 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
15789 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015790 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015791 CHECK_EQ(2, prologue_call_count);
15792 CHECK_EQ(2, epilogue_call_count);
15793 CHECK_EQ(2, prologue_call_count_second);
15794 CHECK_EQ(2, epilogue_call_count_second);
15795 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
15796 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015797 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015798 CHECK_EQ(2, prologue_call_count);
15799 CHECK_EQ(2, epilogue_call_count);
15800 CHECK_EQ(2, prologue_call_count_second);
15801 CHECK_EQ(2, epilogue_call_count_second);
15802}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015803
15804
15805THREADED_TEST(AddToJSFunctionResultCache) {
15806 i::FLAG_allow_natives_syntax = true;
15807 v8::HandleScope scope;
15808
15809 LocalContext context;
15810
15811 const char* code =
15812 "(function() {"
15813 " var key0 = 'a';"
15814 " var key1 = 'b';"
15815 " var r0 = %_GetFromCache(0, key0);"
15816 " var r1 = %_GetFromCache(0, key1);"
15817 " var r0_ = %_GetFromCache(0, key0);"
15818 " if (r0 !== r0_)"
15819 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15820 " var r1_ = %_GetFromCache(0, key1);"
15821 " if (r1 !== r1_)"
15822 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15823 " return 'PASSED';"
15824 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015825 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015826 ExpectString(code, "PASSED");
15827}
15828
15829
15830static const int k0CacheSize = 16;
15831
15832THREADED_TEST(FillJSFunctionResultCache) {
15833 i::FLAG_allow_natives_syntax = true;
15834 v8::HandleScope scope;
15835
15836 LocalContext context;
15837
15838 const char* code =
15839 "(function() {"
15840 " var k = 'a';"
15841 " var r = %_GetFromCache(0, k);"
15842 " for (var i = 0; i < 16; i++) {"
15843 " %_GetFromCache(0, 'a' + i);"
15844 " };"
15845 " if (r === %_GetFromCache(0, k))"
15846 " return 'FAILED: k0CacheSize is too small';"
15847 " return 'PASSED';"
15848 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015849 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015850 ExpectString(code, "PASSED");
15851}
15852
15853
15854THREADED_TEST(RoundRobinGetFromCache) {
15855 i::FLAG_allow_natives_syntax = true;
15856 v8::HandleScope scope;
15857
15858 LocalContext context;
15859
15860 const char* code =
15861 "(function() {"
15862 " var keys = [];"
15863 " for (var i = 0; i < 16; i++) keys.push(i);"
15864 " var values = [];"
15865 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15866 " for (var i = 0; i < 16; i++) {"
15867 " var v = %_GetFromCache(0, keys[i]);"
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000015868 " if (v.toString() !== values[i].toString())"
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015869 " return 'Wrong value for ' + "
15870 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15871 " };"
15872 " return 'PASSED';"
15873 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015874 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015875 ExpectString(code, "PASSED");
15876}
15877
15878
15879THREADED_TEST(ReverseGetFromCache) {
15880 i::FLAG_allow_natives_syntax = true;
15881 v8::HandleScope scope;
15882
15883 LocalContext context;
15884
15885 const char* code =
15886 "(function() {"
15887 " var keys = [];"
15888 " for (var i = 0; i < 16; i++) keys.push(i);"
15889 " var values = [];"
15890 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15891 " for (var i = 15; i >= 16; i--) {"
15892 " var v = %_GetFromCache(0, keys[i]);"
15893 " if (v !== values[i])"
15894 " return 'Wrong value for ' + "
15895 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15896 " };"
15897 " return 'PASSED';"
15898 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015899 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015900 ExpectString(code, "PASSED");
15901}
15902
15903
15904THREADED_TEST(TestEviction) {
15905 i::FLAG_allow_natives_syntax = true;
15906 v8::HandleScope scope;
15907
15908 LocalContext context;
15909
15910 const char* code =
15911 "(function() {"
15912 " for (var i = 0; i < 2*16; i++) {"
15913 " %_GetFromCache(0, 'a' + i);"
15914 " };"
15915 " return 'PASSED';"
15916 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015917 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015918 ExpectString(code, "PASSED");
15919}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015920
15921
15922THREADED_TEST(TwoByteStringInAsciiCons) {
15923 // See Chromium issue 47824.
15924 v8::HandleScope scope;
15925
15926 LocalContext context;
15927 const char* init_code =
15928 "var str1 = 'abelspendabel';"
15929 "var str2 = str1 + str1 + str1;"
15930 "str2;";
15931 Local<Value> result = CompileRun(init_code);
15932
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015933 Local<Value> indexof = CompileRun("str2.indexOf('els')");
15934 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
15935
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015936 CHECK(result->IsString());
15937 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
15938 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000015939 CHECK(string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015940
15941 FlattenString(string);
15942 i::Handle<i::String> flat_string = FlattenGetString(string);
15943
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000015944 CHECK(string->IsOneByteRepresentation());
15945 CHECK(flat_string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015946
15947 // Create external resource.
15948 uint16_t* uc16_buffer = new uint16_t[length + 1];
15949
15950 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15951 uc16_buffer[length] = 0;
15952
15953 TestResource resource(uc16_buffer);
15954
15955 flat_string->MakeExternal(&resource);
15956
15957 CHECK(flat_string->IsTwoByteRepresentation());
15958
15959 // At this point, we should have a Cons string which is flat and ASCII,
15960 // with a first half that is a two-byte string (although it only contains
15961 // ASCII characters). This is a valid sequence of steps, and it can happen
15962 // in real pages.
15963
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000015964 CHECK(string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015965 i::ConsString* cons = i::ConsString::cast(*string);
15966 CHECK_EQ(0, cons->second()->length());
15967 CHECK(cons->first()->IsTwoByteRepresentation());
15968
15969 // Check that some string operations work.
15970
15971 // Atom RegExp.
15972 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15973 CHECK_EQ(6, reresult->Int32Value());
15974
15975 // Nonatom RegExp.
15976 reresult = CompileRun("str2.match(/abe./g).length;");
15977 CHECK_EQ(6, reresult->Int32Value());
15978
15979 reresult = CompileRun("str2.search(/bel/g);");
15980 CHECK_EQ(1, reresult->Int32Value());
15981
15982 reresult = CompileRun("str2.search(/be./g);");
15983 CHECK_EQ(1, reresult->Int32Value());
15984
15985 ExpectTrue("/bel/g.test(str2);");
15986
15987 ExpectTrue("/be./g.test(str2);");
15988
15989 reresult = CompileRun("/bel/g.exec(str2);");
15990 CHECK(!reresult->IsNull());
15991
15992 reresult = CompileRun("/be./g.exec(str2);");
15993 CHECK(!reresult->IsNull());
15994
15995 ExpectString("str2.substring(2, 10);", "elspenda");
15996
15997 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15998
15999 ExpectString("str2.charAt(2);", "e");
16000
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000016001 ExpectObject("str2.indexOf('els');", indexof);
16002
16003 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
16004
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016005 reresult = CompileRun("str2.charCodeAt(2);");
16006 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
16007}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000016008
16009
16010// Failed access check callback that performs a GC on each invocation.
16011void FailedAccessCheckCallbackGC(Local<v8::Object> target,
16012 v8::AccessType type,
16013 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016014 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000016015}
16016
16017
16018TEST(GCInFailedAccessCheckCallback) {
16019 // Install a failed access check callback that performs a GC on each
16020 // invocation. Then force the callback to be called from va
16021
16022 v8::V8::Initialize();
16023 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
16024
16025 v8::HandleScope scope;
16026
16027 // Create an ObjectTemplate for global objects and install access
16028 // check callbacks that will block access.
16029 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
16030 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
16031 IndexedGetAccessBlocker,
16032 v8::Handle<v8::Value>(),
16033 false);
16034
16035 // Create a context and set an x property on it's global object.
16036 LocalContext context0(NULL, global_template);
16037 context0->Global()->Set(v8_str("x"), v8_num(42));
16038 v8::Handle<v8::Object> global0 = context0->Global();
16039
16040 // Create a context with a different security token so that the
16041 // failed access check callback will be called on each access.
16042 LocalContext context1(NULL, global_template);
16043 context1->Global()->Set(v8_str("other"), global0);
16044
16045 // Get property with failed access check.
16046 ExpectUndefined("other.x");
16047
16048 // Get element with failed access check.
16049 ExpectUndefined("other[0]");
16050
16051 // Set property with failed access check.
16052 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
16053 CHECK(result->IsObject());
16054
16055 // Set element with failed access check.
16056 result = CompileRun("other[0] = new Object()");
16057 CHECK(result->IsObject());
16058
16059 // Get property attribute with failed access check.
16060 ExpectFalse("\'x\' in other");
16061
16062 // Get property attribute for element with failed access check.
16063 ExpectFalse("0 in other");
16064
16065 // Delete property.
16066 ExpectFalse("delete other.x");
16067
16068 // Delete element.
16069 CHECK_EQ(false, global0->Delete(0));
16070
16071 // DefineAccessor.
16072 CHECK_EQ(false,
16073 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
16074
16075 // Define JavaScript accessor.
16076 ExpectUndefined("Object.prototype.__defineGetter__.call("
16077 " other, \'x\', function() { return 42; })");
16078
16079 // LookupAccessor.
16080 ExpectUndefined("Object.prototype.__lookupGetter__.call("
16081 " other, \'x\')");
16082
16083 // HasLocalElement.
16084 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
16085
16086 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
16087 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
16088 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
16089
16090 // Reset the failed access check callback so it does not influence
16091 // the other tests.
16092 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
16093}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016095TEST(DefaultIsolateGetCurrent) {
16096 CHECK(v8::Isolate::GetCurrent() != NULL);
16097 v8::Isolate* isolate = v8::Isolate::GetCurrent();
16098 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16099 printf("*** %s\n", "DefaultIsolateGetCurrent success");
16100}
16101
16102TEST(IsolateNewDispose) {
16103 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
16104 v8::Isolate* isolate = v8::Isolate::New();
16105 CHECK(isolate != NULL);
16106 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16107 CHECK(current_isolate != isolate);
16108 CHECK(current_isolate == v8::Isolate::GetCurrent());
16109
16110 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16111 last_location = last_message = NULL;
16112 isolate->Dispose();
16113 CHECK_EQ(last_location, NULL);
16114 CHECK_EQ(last_message, NULL);
16115}
16116
16117TEST(IsolateEnterExitDefault) {
16118 v8::HandleScope scope;
16119 LocalContext context;
16120 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
16121 CHECK(current_isolate != NULL); // Default isolate.
16122 ExpectString("'hello'", "hello");
16123 current_isolate->Enter();
16124 ExpectString("'still working'", "still working");
16125 current_isolate->Exit();
16126 ExpectString("'still working 2'", "still working 2");
16127 current_isolate->Exit();
16128 // Default isolate is always, well, 'default current'.
16129 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
16130 // Still working since default isolate is auto-entering any thread
16131 // that has no isolate and attempts to execute V8 APIs.
16132 ExpectString("'still working 3'", "still working 3");
16133}
16134
16135TEST(DisposeDefaultIsolate) {
16136 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16137
16138 // Run some V8 code to trigger default isolate to become 'current'.
16139 v8::HandleScope scope;
16140 LocalContext context;
16141 ExpectString("'run some V8'", "run some V8");
16142
16143 v8::Isolate* isolate = v8::Isolate::GetCurrent();
16144 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16145 last_location = last_message = NULL;
16146 isolate->Dispose();
16147 // It is not possible to dispose default isolate via Isolate API.
16148 CHECK_NE(last_location, NULL);
16149 CHECK_NE(last_message, NULL);
16150}
16151
16152TEST(RunDefaultAndAnotherIsolate) {
16153 v8::HandleScope scope;
16154 LocalContext context;
16155
16156 // Enter new isolate.
16157 v8::Isolate* isolate = v8::Isolate::New();
16158 CHECK(isolate);
16159 isolate->Enter();
16160 { // Need this block because subsequent Exit() will deallocate Heap,
16161 // so we need all scope objects to be deconstructed when it happens.
16162 v8::HandleScope scope_new;
16163 LocalContext context_new;
16164
16165 // Run something in new isolate.
16166 CompileRun("var foo = 153;");
16167 ExpectTrue("function f() { return foo == 153; }; f()");
16168 }
16169 isolate->Exit();
16170
16171 // This runs automatically in default isolate.
16172 // Variables in another isolate should be not available.
16173 ExpectTrue("function f() {"
16174 " try {"
16175 " foo;"
16176 " return false;"
16177 " } catch(e) {"
16178 " return true;"
16179 " }"
16180 "};"
16181 "var bar = 371;"
16182 "f()");
16183
16184 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16185 last_location = last_message = NULL;
16186 isolate->Dispose();
16187 CHECK_EQ(last_location, NULL);
16188 CHECK_EQ(last_message, NULL);
16189
16190 // Check that default isolate still runs.
16191 ExpectTrue("function f() { return bar == 371; }; f()");
16192}
16193
16194TEST(DisposeIsolateWhenInUse) {
16195 v8::Isolate* isolate = v8::Isolate::New();
16196 CHECK(isolate);
16197 isolate->Enter();
16198 v8::HandleScope scope;
16199 LocalContext context;
16200 // Run something in this isolate.
16201 ExpectTrue("true");
16202 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16203 last_location = last_message = NULL;
16204 // Still entered, should fail.
16205 isolate->Dispose();
16206 CHECK_NE(last_location, NULL);
16207 CHECK_NE(last_message, NULL);
16208}
16209
16210TEST(RunTwoIsolatesOnSingleThread) {
16211 // Run isolate 1.
16212 v8::Isolate* isolate1 = v8::Isolate::New();
16213 isolate1->Enter();
16214 v8::Persistent<v8::Context> context1 = v8::Context::New();
16215
16216 {
16217 v8::Context::Scope cscope(context1);
16218 v8::HandleScope scope;
16219 // Run something in new isolate.
16220 CompileRun("var foo = 'isolate 1';");
16221 ExpectString("function f() { return foo; }; f()", "isolate 1");
16222 }
16223
16224 // Run isolate 2.
16225 v8::Isolate* isolate2 = v8::Isolate::New();
16226 v8::Persistent<v8::Context> context2;
16227
16228 {
16229 v8::Isolate::Scope iscope(isolate2);
16230 context2 = v8::Context::New();
16231 v8::Context::Scope cscope(context2);
16232 v8::HandleScope scope;
16233
16234 // Run something in new isolate.
16235 CompileRun("var foo = 'isolate 2';");
16236 ExpectString("function f() { return foo; }; f()", "isolate 2");
16237 }
16238
16239 {
16240 v8::Context::Scope cscope(context1);
16241 v8::HandleScope scope;
16242 // Now again in isolate 1
16243 ExpectString("function f() { return foo; }; f()", "isolate 1");
16244 }
16245
16246 isolate1->Exit();
16247
16248 // Run some stuff in default isolate.
16249 v8::Persistent<v8::Context> context_default = v8::Context::New();
16250
16251 {
16252 v8::Context::Scope cscope(context_default);
16253 v8::HandleScope scope;
16254 // Variables in other isolates should be not available, verify there
16255 // is an exception.
16256 ExpectTrue("function f() {"
16257 " try {"
16258 " foo;"
16259 " return false;"
16260 " } catch(e) {"
16261 " return true;"
16262 " }"
16263 "};"
16264 "var isDefaultIsolate = true;"
16265 "f()");
16266 }
16267
16268 isolate1->Enter();
16269
16270 {
16271 v8::Isolate::Scope iscope(isolate2);
16272 v8::Context::Scope cscope(context2);
16273 v8::HandleScope scope;
16274 ExpectString("function f() { return foo; }; f()", "isolate 2");
16275 }
16276
16277 {
16278 v8::Context::Scope cscope(context1);
16279 v8::HandleScope scope;
16280 ExpectString("function f() { return foo; }; f()", "isolate 1");
16281 }
16282
16283 {
16284 v8::Isolate::Scope iscope(isolate2);
16285 context2.Dispose();
16286 }
16287
16288 context1.Dispose();
16289 isolate1->Exit();
16290
16291 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16292 last_location = last_message = NULL;
16293
16294 isolate1->Dispose();
16295 CHECK_EQ(last_location, NULL);
16296 CHECK_EQ(last_message, NULL);
16297
16298 isolate2->Dispose();
16299 CHECK_EQ(last_location, NULL);
16300 CHECK_EQ(last_message, NULL);
16301
16302 // Check that default isolate still runs.
16303 {
16304 v8::Context::Scope cscope(context_default);
16305 v8::HandleScope scope;
16306 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
16307 }
16308}
16309
16310static int CalcFibonacci(v8::Isolate* isolate, int limit) {
16311 v8::Isolate::Scope isolate_scope(isolate);
16312 v8::HandleScope scope;
16313 LocalContext context;
16314 i::ScopedVector<char> code(1024);
16315 i::OS::SNPrintF(code, "function fib(n) {"
16316 " if (n <= 2) return 1;"
16317 " return fib(n-1) + fib(n-2);"
16318 "}"
16319 "fib(%d)", limit);
16320 Local<Value> value = CompileRun(code.start());
16321 CHECK(value->IsNumber());
16322 return static_cast<int>(value->NumberValue());
16323}
16324
16325class IsolateThread : public v8::internal::Thread {
16326 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016327 IsolateThread(v8::Isolate* isolate, int fib_limit)
16328 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016329 isolate_(isolate),
16330 fib_limit_(fib_limit),
16331 result_(0) { }
16332
16333 void Run() {
16334 result_ = CalcFibonacci(isolate_, fib_limit_);
16335 }
16336
16337 int result() { return result_; }
16338
16339 private:
16340 v8::Isolate* isolate_;
16341 int fib_limit_;
16342 int result_;
16343};
16344
16345TEST(MultipleIsolatesOnIndividualThreads) {
16346 v8::Isolate* isolate1 = v8::Isolate::New();
16347 v8::Isolate* isolate2 = v8::Isolate::New();
16348
16349 IsolateThread thread1(isolate1, 21);
16350 IsolateThread thread2(isolate2, 12);
16351
16352 // Compute some fibonacci numbers on 3 threads in 3 isolates.
16353 thread1.Start();
16354 thread2.Start();
16355
16356 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
16357 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
16358
16359 thread1.Join();
16360 thread2.Join();
16361
16362 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
16363 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
16364 CHECK_EQ(result1, 10946);
16365 CHECK_EQ(result2, 144);
16366 CHECK_EQ(result1, thread1.result());
16367 CHECK_EQ(result2, thread2.result());
16368
16369 isolate1->Dispose();
16370 isolate2->Dispose();
16371}
16372
lrn@chromium.org1c092762011-05-09 09:42:16 +000016373TEST(IsolateDifferentContexts) {
16374 v8::Isolate* isolate = v8::Isolate::New();
16375 Persistent<v8::Context> context;
16376 {
16377 v8::Isolate::Scope isolate_scope(isolate);
16378 v8::HandleScope handle_scope;
16379 context = v8::Context::New();
16380 v8::Context::Scope context_scope(context);
16381 Local<Value> v = CompileRun("2");
16382 CHECK(v->IsNumber());
16383 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16384 }
16385 {
16386 v8::Isolate::Scope isolate_scope(isolate);
16387 v8::HandleScope handle_scope;
16388 context = v8::Context::New();
16389 v8::Context::Scope context_scope(context);
16390 Local<Value> v = CompileRun("22");
16391 CHECK(v->IsNumber());
16392 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16393 }
16394}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016395
16396class InitDefaultIsolateThread : public v8::internal::Thread {
16397 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016398 enum TestCase {
16399 IgnoreOOM,
16400 SetResourceConstraints,
16401 SetFatalHandler,
16402 SetCounterFunction,
16403 SetCreateHistogramFunction,
16404 SetAddHistogramSampleFunction
16405 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016406
16407 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016408 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016409 testCase_(testCase),
16410 result_(false) { }
16411
16412 void Run() {
16413 switch (testCase_) {
16414 case IgnoreOOM:
16415 v8::V8::IgnoreOutOfMemoryException();
16416 break;
16417
16418 case SetResourceConstraints: {
16419 static const int K = 1024;
16420 v8::ResourceConstraints constraints;
16421 constraints.set_max_young_space_size(256 * K);
16422 constraints.set_max_old_space_size(4 * K * K);
16423 v8::SetResourceConstraints(&constraints);
16424 break;
16425 }
16426
16427 case SetFatalHandler:
16428 v8::V8::SetFatalErrorHandler(NULL);
16429 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016430
16431 case SetCounterFunction:
16432 v8::V8::SetCounterFunction(NULL);
16433 break;
16434
16435 case SetCreateHistogramFunction:
16436 v8::V8::SetCreateHistogramFunction(NULL);
16437 break;
16438
16439 case SetAddHistogramSampleFunction:
16440 v8::V8::SetAddHistogramSampleFunction(NULL);
16441 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016442 }
16443 result_ = true;
16444 }
16445
16446 bool result() { return result_; }
16447
16448 private:
16449 TestCase testCase_;
16450 bool result_;
16451};
16452
16453
16454static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16455 InitDefaultIsolateThread thread(testCase);
16456 thread.Start();
16457 thread.Join();
16458 CHECK_EQ(thread.result(), true);
16459}
16460
16461TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16462 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16463}
16464
16465TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16466 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16467}
16468
16469TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16470 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16471}
16472
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016473TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16474 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16475}
16476
16477TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16478 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16479}
16480
16481TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16482 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16483}
16484
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016485
16486TEST(StringCheckMultipleContexts) {
16487 const char* code =
16488 "(function() { return \"a\".charAt(0); })()";
16489
16490 {
16491 // Run the code twice in the first context to initialize the call IC.
16492 v8::HandleScope scope;
16493 LocalContext context1;
16494 ExpectString(code, "a");
16495 ExpectString(code, "a");
16496 }
16497
16498 {
16499 // Change the String.prototype in the second context and check
16500 // that the right function gets called.
16501 v8::HandleScope scope;
16502 LocalContext context2;
16503 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16504 ExpectString(code, "not a");
16505 }
16506}
16507
16508
16509TEST(NumberCheckMultipleContexts) {
16510 const char* code =
16511 "(function() { return (42).toString(); })()";
16512
16513 {
16514 // Run the code twice in the first context to initialize the call IC.
16515 v8::HandleScope scope;
16516 LocalContext context1;
16517 ExpectString(code, "42");
16518 ExpectString(code, "42");
16519 }
16520
16521 {
16522 // Change the Number.prototype in the second context and check
16523 // that the right function gets called.
16524 v8::HandleScope scope;
16525 LocalContext context2;
16526 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16527 ExpectString(code, "not 42");
16528 }
16529}
16530
16531
16532TEST(BooleanCheckMultipleContexts) {
16533 const char* code =
16534 "(function() { return true.toString(); })()";
16535
16536 {
16537 // Run the code twice in the first context to initialize the call IC.
16538 v8::HandleScope scope;
16539 LocalContext context1;
16540 ExpectString(code, "true");
16541 ExpectString(code, "true");
16542 }
16543
16544 {
16545 // Change the Boolean.prototype in the second context and check
16546 // that the right function gets called.
16547 v8::HandleScope scope;
16548 LocalContext context2;
16549 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16550 ExpectString(code, "");
16551 }
16552}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016553
16554
16555TEST(DontDeleteCellLoadIC) {
16556 const char* function_code =
16557 "function readCell() { while (true) { return cell; } }";
16558
16559 {
16560 // Run the code twice in the first context to initialize the load
16561 // IC for a don't delete cell.
16562 v8::HandleScope scope;
16563 LocalContext context1;
16564 CompileRun("var cell = \"first\";");
16565 ExpectBoolean("delete cell", false);
16566 CompileRun(function_code);
16567 ExpectString("readCell()", "first");
16568 ExpectString("readCell()", "first");
16569 }
16570
16571 {
16572 // Use a deletable cell in the second context.
16573 v8::HandleScope scope;
16574 LocalContext context2;
16575 CompileRun("cell = \"second\";");
16576 CompileRun(function_code);
16577 ExpectString("readCell()", "second");
16578 ExpectBoolean("delete cell", true);
16579 ExpectString("(function() {"
16580 " try {"
16581 " return readCell();"
16582 " } catch(e) {"
16583 " return e.toString();"
16584 " }"
16585 "})()",
16586 "ReferenceError: cell is not defined");
16587 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016588 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016589 ExpectString("readCell()", "new_second");
16590 ExpectString("readCell()", "new_second");
16591 }
16592}
16593
16594
16595TEST(DontDeleteCellLoadICForceDelete) {
16596 const char* function_code =
16597 "function readCell() { while (true) { return cell; } }";
16598
16599 // Run the code twice to initialize the load IC for a don't delete
16600 // cell.
16601 v8::HandleScope scope;
16602 LocalContext context;
16603 CompileRun("var cell = \"value\";");
16604 ExpectBoolean("delete cell", false);
16605 CompileRun(function_code);
16606 ExpectString("readCell()", "value");
16607 ExpectString("readCell()", "value");
16608
16609 // Delete the cell using the API and check the inlined code works
16610 // correctly.
16611 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16612 ExpectString("(function() {"
16613 " try {"
16614 " return readCell();"
16615 " } catch(e) {"
16616 " return e.toString();"
16617 " }"
16618 "})()",
16619 "ReferenceError: cell is not defined");
16620}
16621
16622
16623TEST(DontDeleteCellLoadICAPI) {
16624 const char* function_code =
16625 "function readCell() { while (true) { return cell; } }";
16626
16627 // Run the code twice to initialize the load IC for a don't delete
16628 // cell created using the API.
16629 v8::HandleScope scope;
16630 LocalContext context;
16631 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16632 ExpectBoolean("delete cell", false);
16633 CompileRun(function_code);
16634 ExpectString("readCell()", "value");
16635 ExpectString("readCell()", "value");
16636
16637 // Delete the cell using the API and check the inlined code works
16638 // correctly.
16639 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16640 ExpectString("(function() {"
16641 " try {"
16642 " return readCell();"
16643 " } catch(e) {"
16644 " return e.toString();"
16645 " }"
16646 "})()",
16647 "ReferenceError: cell is not defined");
16648}
16649
16650
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016651class Visitor42 : public v8::PersistentHandleVisitor {
16652 public:
16653 explicit Visitor42(v8::Persistent<v8::Object> object)
16654 : counter_(0), object_(object) { }
16655
16656 virtual void VisitPersistentHandle(Persistent<Value> value,
16657 uint16_t class_id) {
16658 if (class_id == 42) {
16659 CHECK(value->IsObject());
16660 v8::Persistent<v8::Object> visited =
16661 v8::Persistent<v8::Object>::Cast(value);
16662 CHECK_EQ(42, visited.WrapperClassId());
16663 CHECK_EQ(object_, visited);
16664 ++counter_;
16665 }
16666 }
16667
16668 int counter_;
16669 v8::Persistent<v8::Object> object_;
16670};
16671
16672
16673TEST(PersistentHandleVisitor) {
16674 v8::HandleScope scope;
16675 LocalContext context;
16676 v8::Persistent<v8::Object> object =
16677 v8::Persistent<v8::Object>::New(v8::Object::New());
16678 CHECK_EQ(0, object.WrapperClassId());
16679 object.SetWrapperClassId(42);
16680 CHECK_EQ(42, object.WrapperClassId());
16681
16682 Visitor42 visitor(object);
16683 v8::V8::VisitHandlesWithClassIds(&visitor);
16684 CHECK_EQ(1, visitor.counter_);
16685
16686 object.Dispose();
16687}
16688
16689
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000016690TEST(WrapperClassId) {
16691 v8::HandleScope scope;
16692 LocalContext context;
16693 v8::Persistent<v8::Object> object =
16694 v8::Persistent<v8::Object>::New(v8::Object::New());
16695 CHECK_EQ(0, object.WrapperClassId());
16696 object.SetWrapperClassId(65535);
16697 CHECK_EQ(65535, object.WrapperClassId());
16698 object.Dispose();
16699}
16700
16701
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016702TEST(PersistentHandleInNewSpaceVisitor) {
16703 v8::HandleScope scope;
16704 LocalContext context;
16705 v8::Persistent<v8::Object> object1 =
16706 v8::Persistent<v8::Object>::New(v8::Object::New());
16707 CHECK_EQ(0, object1.WrapperClassId());
16708 object1.SetWrapperClassId(42);
16709 CHECK_EQ(42, object1.WrapperClassId());
16710
16711 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16712
16713 v8::Persistent<v8::Object> object2 =
16714 v8::Persistent<v8::Object>::New(v8::Object::New());
16715 CHECK_EQ(0, object2.WrapperClassId());
16716 object2.SetWrapperClassId(42);
16717 CHECK_EQ(42, object2.WrapperClassId());
16718
16719 Visitor42 visitor(object2);
16720 v8::V8::VisitHandlesForPartialDependence(v8::Isolate::GetCurrent(), &visitor);
16721 CHECK_EQ(1, visitor.counter_);
16722
16723 object1.Dispose();
16724 object2.Dispose();
16725}
16726
16727
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016728TEST(RegExp) {
16729 v8::HandleScope scope;
16730 LocalContext context;
16731
16732 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
16733 CHECK(re->IsRegExp());
16734 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016735 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016736
16737 re = v8::RegExp::New(v8_str("bar"),
16738 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16739 v8::RegExp::kGlobal));
16740 CHECK(re->IsRegExp());
16741 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016742 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
16743 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016744
16745 re = v8::RegExp::New(v8_str("baz"),
16746 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16747 v8::RegExp::kMultiline));
16748 CHECK(re->IsRegExp());
16749 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016750 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16751 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016752
16753 re = CompileRun("/quux/").As<v8::RegExp>();
16754 CHECK(re->IsRegExp());
16755 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016756 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016757
16758 re = CompileRun("/quux/gm").As<v8::RegExp>();
16759 CHECK(re->IsRegExp());
16760 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016761 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
16762 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016763
16764 // Override the RegExp constructor and check the API constructor
16765 // still works.
16766 CompileRun("RegExp = function() {}");
16767
16768 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16769 CHECK(re->IsRegExp());
16770 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016771 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016772
16773 re = v8::RegExp::New(v8_str("foobarbaz"),
16774 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16775 v8::RegExp::kMultiline));
16776 CHECK(re->IsRegExp());
16777 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016778 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16779 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016780
16781 context->Global()->Set(v8_str("re"), re);
16782 ExpectTrue("re.test('FoobarbaZ')");
16783
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016784 // RegExps are objects on which you can set properties.
16785 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016786 v8::Handle<v8::Value> value(CompileRun("re.property"));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000016787 CHECK_EQ(32, value->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016788
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016789 v8::TryCatch try_catch;
16790 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16791 CHECK(re.IsEmpty());
16792 CHECK(try_catch.HasCaught());
16793 context->Global()->Set(v8_str("ex"), try_catch.Exception());
16794 ExpectTrue("ex instanceof SyntaxError");
16795}
16796
16797
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016798THREADED_TEST(Equals) {
16799 v8::HandleScope handleScope;
16800 LocalContext localContext;
16801
16802 v8::Handle<v8::Object> globalProxy = localContext->Global();
16803 v8::Handle<Value> global = globalProxy->GetPrototype();
16804
16805 CHECK(global->StrictEquals(global));
16806 CHECK(!global->StrictEquals(globalProxy));
16807 CHECK(!globalProxy->StrictEquals(global));
16808 CHECK(globalProxy->StrictEquals(globalProxy));
16809
16810 CHECK(global->Equals(global));
16811 CHECK(!global->Equals(globalProxy));
16812 CHECK(!globalProxy->Equals(global));
16813 CHECK(globalProxy->Equals(globalProxy));
16814}
16815
16816
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016817static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16818 const v8::AccessorInfo& info ) {
16819 return v8_str("42!");
16820}
16821
16822
16823static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16824 v8::Handle<v8::Array> result = v8::Array::New();
16825 result->Set(0, v8_str("universalAnswer"));
16826 return result;
16827}
16828
16829
16830TEST(NamedEnumeratorAndForIn) {
16831 v8::HandleScope handle_scope;
16832 LocalContext context;
16833 v8::Context::Scope context_scope(context.local());
16834
16835 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
16836 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16837 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16838 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
16839 "var result = []; for (var k in o) result.push(k); result"));
16840 CHECK_EQ(1, result->Length());
16841 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16842}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016843
16844
16845TEST(DefinePropertyPostDetach) {
16846 v8::HandleScope scope;
16847 LocalContext context;
16848 v8::Handle<v8::Object> proxy = context->Global();
16849 v8::Handle<v8::Function> define_property =
16850 CompileRun("(function() {"
16851 " Object.defineProperty("
16852 " this,"
16853 " 1,"
16854 " { configurable: true, enumerable: true, value: 3 });"
16855 "})").As<Function>();
16856 context->DetachGlobal();
16857 define_property->Call(proxy, 0, NULL);
16858}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016859
16860
16861static void InstallContextId(v8::Handle<Context> context, int id) {
16862 Context::Scope scope(context);
16863 CompileRun("Object.prototype").As<Object>()->
16864 Set(v8_str("context_id"), v8::Integer::New(id));
16865}
16866
16867
16868static void CheckContextId(v8::Handle<Object> object, int expected) {
16869 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16870}
16871
16872
16873THREADED_TEST(CreationContext) {
16874 HandleScope handle_scope;
16875 Persistent<Context> context1 = Context::New();
16876 InstallContextId(context1, 1);
16877 Persistent<Context> context2 = Context::New();
16878 InstallContextId(context2, 2);
16879 Persistent<Context> context3 = Context::New();
16880 InstallContextId(context3, 3);
16881
16882 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16883
16884 Local<Object> object1;
16885 Local<Function> func1;
16886 {
16887 Context::Scope scope(context1);
16888 object1 = Object::New();
16889 func1 = tmpl->GetFunction();
16890 }
16891
16892 Local<Object> object2;
16893 Local<Function> func2;
16894 {
16895 Context::Scope scope(context2);
16896 object2 = Object::New();
16897 func2 = tmpl->GetFunction();
16898 }
16899
16900 Local<Object> instance1;
16901 Local<Object> instance2;
16902
16903 {
16904 Context::Scope scope(context3);
16905 instance1 = func1->NewInstance();
16906 instance2 = func2->NewInstance();
16907 }
16908
16909 CHECK(object1->CreationContext() == context1);
16910 CheckContextId(object1, 1);
16911 CHECK(func1->CreationContext() == context1);
16912 CheckContextId(func1, 1);
16913 CHECK(instance1->CreationContext() == context1);
16914 CheckContextId(instance1, 1);
16915 CHECK(object2->CreationContext() == context2);
16916 CheckContextId(object2, 2);
16917 CHECK(func2->CreationContext() == context2);
16918 CheckContextId(func2, 2);
16919 CHECK(instance2->CreationContext() == context2);
16920 CheckContextId(instance2, 2);
16921
16922 {
16923 Context::Scope scope(context1);
16924 CHECK(object1->CreationContext() == context1);
16925 CheckContextId(object1, 1);
16926 CHECK(func1->CreationContext() == context1);
16927 CheckContextId(func1, 1);
16928 CHECK(instance1->CreationContext() == context1);
16929 CheckContextId(instance1, 1);
16930 CHECK(object2->CreationContext() == context2);
16931 CheckContextId(object2, 2);
16932 CHECK(func2->CreationContext() == context2);
16933 CheckContextId(func2, 2);
16934 CHECK(instance2->CreationContext() == context2);
16935 CheckContextId(instance2, 2);
16936 }
16937
16938 {
16939 Context::Scope scope(context2);
16940 CHECK(object1->CreationContext() == context1);
16941 CheckContextId(object1, 1);
16942 CHECK(func1->CreationContext() == context1);
16943 CheckContextId(func1, 1);
16944 CHECK(instance1->CreationContext() == context1);
16945 CheckContextId(instance1, 1);
16946 CHECK(object2->CreationContext() == context2);
16947 CheckContextId(object2, 2);
16948 CHECK(func2->CreationContext() == context2);
16949 CheckContextId(func2, 2);
16950 CHECK(instance2->CreationContext() == context2);
16951 CheckContextId(instance2, 2);
16952 }
16953
16954 context1.Dispose();
16955 context2.Dispose();
16956 context3.Dispose();
16957}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016958
16959
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000016960THREADED_TEST(CreationContextOfJsFunction) {
16961 HandleScope handle_scope;
16962 Persistent<Context> context = Context::New();
16963 InstallContextId(context, 1);
16964
16965 Local<Object> function;
16966 {
16967 Context::Scope scope(context);
16968 function = CompileRun("function foo() {}; foo").As<Object>();
16969 }
16970
16971 CHECK(function->CreationContext() == context);
16972 CheckContextId(function, 1);
16973
16974 context.Dispose();
16975}
16976
16977
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016978Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16979 const AccessorInfo& info) {
16980 if (index == 42) return v8_str("yes");
16981 return Handle<v8::Integer>();
16982}
16983
16984
16985Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
16986 const AccessorInfo& info) {
16987 if (property->Equals(v8_str("foo"))) return v8_str("yes");
16988 return Handle<Value>();
16989}
16990
16991
16992Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
16993 uint32_t index, const AccessorInfo& info) {
16994 if (index == 42) return v8_num(1).As<v8::Integer>();
16995 return Handle<v8::Integer>();
16996}
16997
16998
16999Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
17000 Local<String> property, const AccessorInfo& info) {
17001 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
17002 return Handle<v8::Integer>();
17003}
17004
17005
17006Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
17007 Local<String> property, const AccessorInfo& info) {
17008 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
17009 return Handle<v8::Integer>();
17010}
17011
17012
17013Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
17014 const AccessorInfo& info) {
17015 return v8_str("yes");
17016}
17017
17018
17019TEST(HasOwnProperty) {
17020 v8::HandleScope scope;
17021 LocalContext env;
17022 { // Check normal properties and defined getters.
17023 Handle<Value> value = CompileRun(
17024 "function Foo() {"
17025 " this.foo = 11;"
17026 " this.__defineGetter__('baz', function() { return 1; });"
17027 "};"
17028 "function Bar() { "
17029 " this.bar = 13;"
17030 " this.__defineGetter__('bla', function() { return 2; });"
17031 "};"
17032 "Bar.prototype = new Foo();"
17033 "new Bar();");
17034 CHECK(value->IsObject());
17035 Handle<Object> object = value->ToObject();
17036 CHECK(object->Has(v8_str("foo")));
17037 CHECK(!object->HasOwnProperty(v8_str("foo")));
17038 CHECK(object->HasOwnProperty(v8_str("bar")));
17039 CHECK(object->Has(v8_str("baz")));
17040 CHECK(!object->HasOwnProperty(v8_str("baz")));
17041 CHECK(object->HasOwnProperty(v8_str("bla")));
17042 }
17043 { // Check named getter interceptors.
17044 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17045 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
17046 Handle<Object> instance = templ->NewInstance();
17047 CHECK(!instance->HasOwnProperty(v8_str("42")));
17048 CHECK(instance->HasOwnProperty(v8_str("foo")));
17049 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17050 }
17051 { // Check indexed getter interceptors.
17052 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17053 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
17054 Handle<Object> instance = templ->NewInstance();
17055 CHECK(instance->HasOwnProperty(v8_str("42")));
17056 CHECK(!instance->HasOwnProperty(v8_str("43")));
17057 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17058 }
17059 { // Check named query interceptors.
17060 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17061 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
17062 Handle<Object> instance = templ->NewInstance();
17063 CHECK(instance->HasOwnProperty(v8_str("foo")));
17064 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17065 }
17066 { // Check indexed query interceptors.
17067 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17068 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
17069 Handle<Object> instance = templ->NewInstance();
17070 CHECK(instance->HasOwnProperty(v8_str("42")));
17071 CHECK(!instance->HasOwnProperty(v8_str("41")));
17072 }
17073 { // Check callbacks.
17074 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17075 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
17076 Handle<Object> instance = templ->NewInstance();
17077 CHECK(instance->HasOwnProperty(v8_str("foo")));
17078 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17079 }
17080 { // Check that query wins on disagreement.
17081 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17082 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
17083 0,
17084 HasOwnPropertyNamedPropertyQuery2);
17085 Handle<Object> instance = templ->NewInstance();
17086 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17087 CHECK(instance->HasOwnProperty(v8_str("bar")));
17088 }
17089}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017090
17091
17092void CheckCodeGenerationAllowed() {
17093 Handle<Value> result = CompileRun("eval('42')");
17094 CHECK_EQ(42, result->Int32Value());
17095 result = CompileRun("(function(e) { return e('42'); })(eval)");
17096 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017097 result = CompileRun("var f = new Function('return 42'); f()");
17098 CHECK_EQ(42, result->Int32Value());
17099}
17100
17101
17102void CheckCodeGenerationDisallowed() {
17103 TryCatch try_catch;
17104
17105 Handle<Value> result = CompileRun("eval('42')");
17106 CHECK(result.IsEmpty());
17107 CHECK(try_catch.HasCaught());
17108 try_catch.Reset();
17109
17110 result = CompileRun("(function(e) { return e('42'); })(eval)");
17111 CHECK(result.IsEmpty());
17112 CHECK(try_catch.HasCaught());
17113 try_catch.Reset();
17114
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017115 result = CompileRun("var f = new Function('return 42'); f()");
17116 CHECK(result.IsEmpty());
17117 CHECK(try_catch.HasCaught());
17118}
17119
17120
17121bool CodeGenerationAllowed(Local<Context> context) {
17122 ApiTestFuzzer::Fuzz();
17123 return true;
17124}
17125
17126
17127bool CodeGenerationDisallowed(Local<Context> context) {
17128 ApiTestFuzzer::Fuzz();
17129 return false;
17130}
17131
17132
17133THREADED_TEST(AllowCodeGenFromStrings) {
17134 v8::HandleScope scope;
17135 LocalContext context;
17136
ager@chromium.orgea91cc52011-05-23 06:06:11 +000017137 // eval and the Function constructor allowed by default.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017138 CHECK(context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017139 CheckCodeGenerationAllowed();
17140
ager@chromium.orgea91cc52011-05-23 06:06:11 +000017141 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017142 context->AllowCodeGenerationFromStrings(false);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017143 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017144 CheckCodeGenerationDisallowed();
17145
17146 // Allow again.
17147 context->AllowCodeGenerationFromStrings(true);
17148 CheckCodeGenerationAllowed();
17149
17150 // Disallow but setting a global callback that will allow the calls.
17151 context->AllowCodeGenerationFromStrings(false);
17152 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017153 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017154 CheckCodeGenerationAllowed();
17155
17156 // Set a callback that disallows the code generation.
17157 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017158 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017159 CheckCodeGenerationDisallowed();
17160}
lrn@chromium.org1c092762011-05-09 09:42:16 +000017161
17162
ulan@chromium.org56c14af2012-09-20 12:51:09 +000017163TEST(SetErrorMessageForCodeGenFromStrings) {
17164 v8::HandleScope scope;
17165 LocalContext context;
17166 TryCatch try_catch;
17167
17168 Handle<String> message = v8_str("Message") ;
17169 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
17170 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17171 context->AllowCodeGenerationFromStrings(false);
17172 context->SetErrorMessageForCodeGenerationFromStrings(message);
17173 Handle<Value> result = CompileRun("eval('42')");
17174 CHECK(result.IsEmpty());
17175 CHECK(try_catch.HasCaught());
17176 Handle<String> actual_message = try_catch.Message()->Get();
17177 CHECK(expected_message->Equals(actual_message));
17178}
17179
17180
lrn@chromium.org1c092762011-05-09 09:42:16 +000017181static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
17182 return v8::Undefined();
17183}
17184
17185
17186THREADED_TEST(CallAPIFunctionOnNonObject) {
17187 v8::HandleScope scope;
17188 LocalContext context;
17189 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
17190 Handle<Function> function = templ->GetFunction();
17191 context->Global()->Set(v8_str("f"), function);
17192 TryCatch try_catch;
17193 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000017194}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000017195
17196
17197// Regression test for issue 1470.
17198THREADED_TEST(ReadOnlyIndexedProperties) {
17199 v8::HandleScope scope;
17200 Local<ObjectTemplate> templ = ObjectTemplate::New();
17201
17202 LocalContext context;
17203 Local<v8::Object> obj = templ->NewInstance();
17204 context->Global()->Set(v8_str("obj"), obj);
17205 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17206 obj->Set(v8_str("1"), v8_str("foobar"));
17207 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
17208 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
17209 obj->Set(v8_num(2), v8_str("foobar"));
17210 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
17211
17212 // Test non-smi case.
17213 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17214 obj->Set(v8_str("2000000000"), v8_str("foobar"));
17215 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
17216}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017217
17218
17219THREADED_TEST(Regress1516) {
17220 v8::HandleScope scope;
17221
17222 LocalContext context;
17223 { v8::HandleScope temp_scope;
17224 CompileRun("({'a': 0})");
17225 }
17226
17227 int elements;
17228 { i::MapCache* map_cache =
17229 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
17230 elements = map_cache->NumberOfElements();
17231 CHECK_LE(1, elements);
17232 }
17233
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +000017234 i::Isolate::Current()->heap()->CollectAllGarbage(
17235 i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017236 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
17237 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
17238 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
17239 CHECK_GT(elements, map_cache->NumberOfElements());
17240 }
17241 }
17242}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017243
17244
17245static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
17246 Local<Value> name,
17247 v8::AccessType type,
17248 Local<Value> data) {
17249 // Only block read access to __proto__.
17250 if (type == v8::ACCESS_GET &&
17251 name->IsString() &&
17252 name->ToString()->Length() == 9 &&
17253 name->ToString()->Utf8Length() == 9) {
17254 char buffer[10];
17255 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
17256 return strncmp(buffer, "__proto__", 9) != 0;
17257 }
17258
17259 return true;
17260}
17261
17262
17263THREADED_TEST(Regress93759) {
17264 HandleScope scope;
17265
17266 // Template for object with security check.
17267 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
17268 // We don't do indexing, so any callback can be used for that.
17269 no_proto_template->SetAccessCheckCallbacks(
17270 BlockProtoNamedSecurityTestCallback,
17271 IndexedSecurityTestCallback);
17272
17273 // Templates for objects with hidden prototypes and possibly security check.
17274 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
17275 hidden_proto_template->SetHiddenPrototype(true);
17276
17277 Local<FunctionTemplate> protected_hidden_proto_template =
17278 v8::FunctionTemplate::New();
17279 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
17280 BlockProtoNamedSecurityTestCallback,
17281 IndexedSecurityTestCallback);
17282 protected_hidden_proto_template->SetHiddenPrototype(true);
17283
17284 // Context for "foreign" objects used in test.
17285 Persistent<Context> context = v8::Context::New();
17286 context->Enter();
17287
17288 // Plain object, no security check.
17289 Local<Object> simple_object = Object::New();
17290
17291 // Object with explicit security check.
17292 Local<Object> protected_object =
17293 no_proto_template->NewInstance();
17294
17295 // JSGlobalProxy object, always have security check.
17296 Local<Object> proxy_object =
17297 context->Global();
17298
17299 // Global object, the prototype of proxy_object. No security checks.
17300 Local<Object> global_object =
17301 proxy_object->GetPrototype()->ToObject();
17302
17303 // Hidden prototype without security check.
17304 Local<Object> hidden_prototype =
17305 hidden_proto_template->GetFunction()->NewInstance();
17306 Local<Object> object_with_hidden =
17307 Object::New();
17308 object_with_hidden->SetPrototype(hidden_prototype);
17309
17310 // Hidden prototype with security check on the hidden prototype.
17311 Local<Object> protected_hidden_prototype =
17312 protected_hidden_proto_template->GetFunction()->NewInstance();
17313 Local<Object> object_with_protected_hidden =
17314 Object::New();
17315 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
17316
17317 context->Exit();
17318
17319 // Template for object for second context. Values to test are put on it as
17320 // properties.
17321 Local<ObjectTemplate> global_template = ObjectTemplate::New();
17322 global_template->Set(v8_str("simple"), simple_object);
17323 global_template->Set(v8_str("protected"), protected_object);
17324 global_template->Set(v8_str("global"), global_object);
17325 global_template->Set(v8_str("proxy"), proxy_object);
17326 global_template->Set(v8_str("hidden"), object_with_hidden);
17327 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
17328
17329 LocalContext context2(NULL, global_template);
17330
17331 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
17332 CHECK(result1->Equals(simple_object->GetPrototype()));
17333
17334 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
17335 CHECK(result2->Equals(Undefined()));
17336
17337 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
17338 CHECK(result3->Equals(global_object->GetPrototype()));
17339
17340 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
17341 CHECK(result4->Equals(Undefined()));
17342
17343 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
17344 CHECK(result5->Equals(
17345 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
17346
17347 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
17348 CHECK(result6->Equals(Undefined()));
17349
17350 context.Dispose();
17351}
17352
17353
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000017354THREADED_TEST(Regress125988) {
17355 v8::HandleScope scope;
17356 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
17357 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
17358 LocalContext env;
17359 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
17360 CompileRun("var a = new Object();"
17361 "var b = new Intercept();"
17362 "var c = new Object();"
17363 "c.__proto__ = b;"
17364 "b.__proto__ = a;"
17365 "a.x = 23;"
17366 "for (var i = 0; i < 3; i++) c.x;");
17367 ExpectBoolean("c.hasOwnProperty('x')", false);
17368 ExpectInt32("c.x", 23);
17369 CompileRun("a.y = 42;"
17370 "for (var i = 0; i < 3; i++) c.x;");
17371 ExpectBoolean("c.hasOwnProperty('x')", false);
17372 ExpectInt32("c.x", 23);
17373 ExpectBoolean("c.hasOwnProperty('y')", false);
17374 ExpectInt32("c.y", 42);
17375}
17376
17377
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017378static void TestReceiver(Local<Value> expected_result,
17379 Local<Value> expected_receiver,
17380 const char* code) {
17381 Local<Value> result = CompileRun(code);
17382 CHECK(result->IsObject());
17383 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
17384 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
17385}
17386
17387
17388THREADED_TEST(ForeignFunctionReceiver) {
17389 HandleScope scope;
17390
17391 // Create two contexts with different "id" properties ('i' and 'o').
17392 // Call a function both from its own context and from a the foreign
17393 // context, and see what "this" is bound to (returning both "this"
17394 // and "this.id" for comparison).
17395
17396 Persistent<Context> foreign_context = v8::Context::New();
17397 foreign_context->Enter();
17398 Local<Value> foreign_function =
17399 CompileRun("function func() { return { 0: this.id, "
17400 " 1: this, "
17401 " toString: function() { "
17402 " return this[0];"
17403 " }"
17404 " };"
17405 "}"
17406 "var id = 'i';"
17407 "func;");
17408 CHECK(foreign_function->IsFunction());
17409 foreign_context->Exit();
17410
17411 LocalContext context;
17412
17413 Local<String> password = v8_str("Password");
17414 // Don't get hit by security checks when accessing foreign_context's
17415 // global receiver (aka. global proxy).
17416 context->SetSecurityToken(password);
17417 foreign_context->SetSecurityToken(password);
17418
17419 Local<String> i = v8_str("i");
17420 Local<String> o = v8_str("o");
17421 Local<String> id = v8_str("id");
17422
17423 CompileRun("function ownfunc() { return { 0: this.id, "
17424 " 1: this, "
17425 " toString: function() { "
17426 " return this[0];"
17427 " }"
17428 " };"
17429 "}"
17430 "var id = 'o';"
17431 "ownfunc");
17432 context->Global()->Set(v8_str("func"), foreign_function);
17433
17434 // Sanity check the contexts.
17435 CHECK(i->Equals(foreign_context->Global()->Get(id)));
17436 CHECK(o->Equals(context->Global()->Get(id)));
17437
17438 // Checking local function's receiver.
17439 // Calling function using its call/apply methods.
17440 TestReceiver(o, context->Global(), "ownfunc.call()");
17441 TestReceiver(o, context->Global(), "ownfunc.apply()");
17442 // Making calls through built-in functions.
17443 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17444 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17445 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17446 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17447 // Calling with environment record as base.
17448 TestReceiver(o, context->Global(), "ownfunc()");
17449 // Calling with no base.
17450 TestReceiver(o, context->Global(), "(1,ownfunc)()");
17451
17452 // Checking foreign function return value.
17453 // Calling function using its call/apply methods.
17454 TestReceiver(i, foreign_context->Global(), "func.call()");
17455 TestReceiver(i, foreign_context->Global(), "func.apply()");
17456 // Calling function using another context's call/apply methods.
17457 TestReceiver(i, foreign_context->Global(),
17458 "Function.prototype.call.call(func)");
17459 TestReceiver(i, foreign_context->Global(),
17460 "Function.prototype.call.apply(func)");
17461 TestReceiver(i, foreign_context->Global(),
17462 "Function.prototype.apply.call(func)");
17463 TestReceiver(i, foreign_context->Global(),
17464 "Function.prototype.apply.apply(func)");
17465 // Making calls through built-in functions.
17466 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17467 // ToString(func()) is func()[0], i.e., the returned this.id.
17468 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17469 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17470 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17471
17472 // TODO(1547): Make the following also return "i".
17473 // Calling with environment record as base.
17474 TestReceiver(o, context->Global(), "func()");
17475 // Calling with no base.
17476 TestReceiver(o, context->Global(), "(1,func)()");
17477
17478 foreign_context.Dispose();
17479}
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017480
17481
17482uint8_t callback_fired = 0;
17483
17484
17485void CallCompletedCallback1() {
17486 i::OS::Print("Firing callback 1.\n");
17487 callback_fired ^= 1; // Toggle first bit.
17488}
17489
17490
17491void CallCompletedCallback2() {
17492 i::OS::Print("Firing callback 2.\n");
17493 callback_fired ^= 2; // Toggle second bit.
17494}
17495
17496
17497Handle<Value> RecursiveCall(const Arguments& args) {
17498 int32_t level = args[0]->Int32Value();
17499 if (level < 3) {
17500 level++;
17501 i::OS::Print("Entering recursion level %d.\n", level);
17502 char script[64];
17503 i::Vector<char> script_vector(script, sizeof(script));
17504 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17505 CompileRun(script_vector.start());
17506 i::OS::Print("Leaving recursion level %d.\n", level);
17507 CHECK_EQ(0, callback_fired);
17508 } else {
17509 i::OS::Print("Recursion ends.\n");
17510 CHECK_EQ(0, callback_fired);
17511 }
17512 return Undefined();
17513}
17514
17515
17516TEST(CallCompletedCallback) {
17517 v8::HandleScope scope;
17518 LocalContext env;
17519 v8::Handle<v8::FunctionTemplate> recursive_runtime =
17520 v8::FunctionTemplate::New(RecursiveCall);
17521 env->Global()->Set(v8_str("recursion"),
17522 recursive_runtime->GetFunction());
17523 // Adding the same callback a second time has no effect.
17524 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17525 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17526 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
17527 i::OS::Print("--- Script (1) ---\n");
17528 Local<Script> script =
17529 v8::Script::Compile(v8::String::New("recursion(0)"));
17530 script->Run();
17531 CHECK_EQ(3, callback_fired);
17532
17533 i::OS::Print("\n--- Script (2) ---\n");
17534 callback_fired = 0;
17535 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17536 script->Run();
17537 CHECK_EQ(2, callback_fired);
17538
17539 i::OS::Print("\n--- Function ---\n");
17540 callback_fired = 0;
17541 Local<Function> recursive_function =
17542 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17543 v8::Handle<Value> args[] = { v8_num(0) };
17544 recursive_function->Call(env->Global(), 1, args);
17545 CHECK_EQ(2, callback_fired);
17546}
17547
17548
17549void CallCompletedCallbackNoException() {
17550 v8::HandleScope scope;
17551 CompileRun("1+1;");
17552}
17553
17554
17555void CallCompletedCallbackException() {
17556 v8::HandleScope scope;
17557 CompileRun("throw 'second exception';");
17558}
17559
17560
17561TEST(CallCompletedCallbackOneException) {
17562 v8::HandleScope scope;
17563 LocalContext env;
17564 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17565 CompileRun("throw 'exception';");
17566}
17567
17568
17569TEST(CallCompletedCallbackTwoExceptions) {
17570 v8::HandleScope scope;
17571 LocalContext env;
17572 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17573 CompileRun("throw 'first exception';");
17574}
ulan@chromium.org812308e2012-02-29 15:58:45 +000017575
17576
17577static int probes_counter = 0;
17578static int misses_counter = 0;
17579static int updates_counter = 0;
17580
17581
17582static int* LookupCounter(const char* name) {
17583 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17584 return &probes_counter;
17585 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17586 return &misses_counter;
17587 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17588 return &updates_counter;
17589 }
17590 return NULL;
17591}
17592
17593
17594static const char* kMegamorphicTestProgram =
17595 "function ClassA() { };"
17596 "function ClassB() { };"
17597 "ClassA.prototype.foo = function() { };"
17598 "ClassB.prototype.foo = function() { };"
17599 "function fooify(obj) { obj.foo(); };"
17600 "var a = new ClassA();"
17601 "var b = new ClassB();"
17602 "for (var i = 0; i < 10000; i++) {"
17603 " fooify(a);"
17604 " fooify(b);"
17605 "}";
17606
17607
17608static void StubCacheHelper(bool primary) {
17609 V8::SetCounterFunction(LookupCounter);
17610 USE(kMegamorphicTestProgram);
17611#ifdef DEBUG
17612 i::FLAG_native_code_counters = true;
17613 if (primary) {
17614 i::FLAG_test_primary_stub_cache = true;
17615 } else {
17616 i::FLAG_test_secondary_stub_cache = true;
17617 }
17618 i::FLAG_crankshaft = false;
17619 v8::HandleScope scope;
17620 LocalContext env;
17621 int initial_probes = probes_counter;
17622 int initial_misses = misses_counter;
17623 int initial_updates = updates_counter;
17624 CompileRun(kMegamorphicTestProgram);
17625 int probes = probes_counter - initial_probes;
17626 int misses = misses_counter - initial_misses;
17627 int updates = updates_counter - initial_updates;
17628 CHECK_LT(updates, 10);
17629 CHECK_LT(misses, 10);
17630 CHECK_GE(probes, 10000);
17631#endif
17632}
17633
17634
17635TEST(SecondaryStubCache) {
17636 StubCacheHelper(true);
17637}
17638
17639
17640TEST(PrimaryStubCache) {
17641 StubCacheHelper(false);
17642}
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017643
17644
17645static int fatal_error_callback_counter = 0;
17646static void CountingErrorCallback(const char* location, const char* message) {
17647 printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17648 fatal_error_callback_counter++;
17649}
17650
17651
17652TEST(StaticGetters) {
17653 v8::HandleScope scope;
17654 LocalContext context;
17655 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17656 i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17657 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17658 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17659 i::Handle<i::Object> null_value = FACTORY->null_value();
17660 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17661 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17662 i::Handle<i::Object> true_value = FACTORY->true_value();
17663 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17664 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17665 i::Handle<i::Object> false_value = FACTORY->false_value();
17666 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17667 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17668
17669 // Test after-death behavior.
17670 CHECK(i::Internals::IsInitialized(isolate));
17671 CHECK_EQ(0, fatal_error_callback_counter);
17672 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17673 v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17674 i::Isolate::Current()->TearDown();
17675 CHECK(!i::Internals::IsInitialized(isolate));
17676 CHECK_EQ(1, fatal_error_callback_counter);
17677 CHECK(v8::Undefined().IsEmpty());
17678 CHECK_EQ(2, fatal_error_callback_counter);
17679 CHECK(v8::Undefined(isolate).IsEmpty());
17680 CHECK_EQ(3, fatal_error_callback_counter);
17681 CHECK(v8::Null().IsEmpty());
17682 CHECK_EQ(4, fatal_error_callback_counter);
17683 CHECK(v8::Null(isolate).IsEmpty());
17684 CHECK_EQ(5, fatal_error_callback_counter);
17685 CHECK(v8::True().IsEmpty());
17686 CHECK_EQ(6, fatal_error_callback_counter);
17687 CHECK(v8::True(isolate).IsEmpty());
17688 CHECK_EQ(7, fatal_error_callback_counter);
17689 CHECK(v8::False().IsEmpty());
17690 CHECK_EQ(8, fatal_error_callback_counter);
17691 CHECK(v8::False(isolate).IsEmpty());
17692 CHECK_EQ(9, fatal_error_callback_counter);
17693}
17694
17695
17696TEST(IsolateEmbedderData) {
17697 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17698 CHECK_EQ(NULL, isolate->GetData());
17699 CHECK_EQ(NULL, ISOLATE->GetData());
17700 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17701 isolate->SetData(data1);
17702 CHECK_EQ(data1, isolate->GetData());
17703 CHECK_EQ(data1, ISOLATE->GetData());
17704 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17705 ISOLATE->SetData(data2);
17706 CHECK_EQ(data2, isolate->GetData());
17707 CHECK_EQ(data2, ISOLATE->GetData());
17708 ISOLATE->TearDown();
17709 CHECK_EQ(data2, isolate->GetData());
17710 CHECK_EQ(data2, ISOLATE->GetData());
17711}
17712
17713
17714TEST(StringEmpty) {
17715 v8::HandleScope scope;
17716 LocalContext context;
17717 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17718 i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
17719 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17720 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17721
17722 // Test after-death behavior.
17723 CHECK(i::Internals::IsInitialized(isolate));
17724 CHECK_EQ(0, fatal_error_callback_counter);
17725 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17726 v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17727 i::Isolate::Current()->TearDown();
17728 CHECK(!i::Internals::IsInitialized(isolate));
17729 CHECK_EQ(1, fatal_error_callback_counter);
17730 CHECK(v8::String::Empty().IsEmpty());
17731 CHECK_EQ(2, fatal_error_callback_counter);
17732 CHECK(v8::String::Empty(isolate).IsEmpty());
17733 CHECK_EQ(3, fatal_error_callback_counter);
17734}
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017735
17736
17737static int instance_checked_getter_count = 0;
17738static Handle<Value> InstanceCheckedGetter(Local<String> name,
17739 const AccessorInfo& info) {
17740 CHECK_EQ(name, v8_str("foo"));
17741 instance_checked_getter_count++;
17742 return v8_num(11);
17743}
17744
17745
17746static int instance_checked_setter_count = 0;
17747static void InstanceCheckedSetter(Local<String> name,
17748 Local<Value> value,
17749 const AccessorInfo& info) {
17750 CHECK_EQ(name, v8_str("foo"));
17751 CHECK_EQ(value, v8_num(23));
17752 instance_checked_setter_count++;
17753}
17754
17755
17756static void CheckInstanceCheckedResult(int getters,
17757 int setters,
17758 bool expects_callbacks,
17759 TryCatch* try_catch) {
17760 if (expects_callbacks) {
17761 CHECK(!try_catch->HasCaught());
17762 CHECK_EQ(getters, instance_checked_getter_count);
17763 CHECK_EQ(setters, instance_checked_setter_count);
17764 } else {
17765 CHECK(try_catch->HasCaught());
17766 CHECK_EQ(0, instance_checked_getter_count);
17767 CHECK_EQ(0, instance_checked_setter_count);
17768 }
17769 try_catch->Reset();
17770}
17771
17772
17773static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17774 instance_checked_getter_count = 0;
17775 instance_checked_setter_count = 0;
17776 TryCatch try_catch;
17777
17778 // Test path through generic runtime code.
17779 CompileRun("obj.foo");
17780 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17781 CompileRun("obj.foo = 23");
17782 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17783
17784 // Test path through generated LoadIC and StoredIC.
17785 CompileRun("function test_get(o) { o.foo; }"
17786 "test_get(obj);");
17787 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17788 CompileRun("test_get(obj);");
17789 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17790 CompileRun("test_get(obj);");
17791 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17792 CompileRun("function test_set(o) { o.foo = 23; }"
17793 "test_set(obj);");
17794 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17795 CompileRun("test_set(obj);");
17796 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17797 CompileRun("test_set(obj);");
17798 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17799
17800 // Test path through optimized code.
17801 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17802 "test_get(obj);");
17803 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17804 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17805 "test_set(obj);");
17806 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17807
17808 // Cleanup so that closures start out fresh in next check.
17809 CompileRun("%DeoptimizeFunction(test_get);"
17810 "%ClearFunctionTypeFeedback(test_get);"
17811 "%DeoptimizeFunction(test_set);"
17812 "%ClearFunctionTypeFeedback(test_set);");
17813}
17814
17815
17816THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17817 v8::internal::FLAG_allow_natives_syntax = true;
17818 v8::HandleScope scope;
17819 LocalContext context;
17820
17821 Local<FunctionTemplate> templ = FunctionTemplate::New();
17822 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17823 inst->SetAccessor(v8_str("foo"),
17824 InstanceCheckedGetter, InstanceCheckedSetter,
17825 Handle<Value>(),
17826 v8::DEFAULT,
17827 v8::None,
17828 v8::AccessorSignature::New(templ));
17829 context->Global()->Set(v8_str("f"), templ->GetFunction());
17830
17831 printf("Testing positive ...\n");
17832 CompileRun("var obj = new f();");
17833 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17834 CheckInstanceCheckedAccessors(true);
17835
17836 printf("Testing negative ...\n");
17837 CompileRun("var obj = {};"
17838 "obj.__proto__ = new f();");
17839 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17840 CheckInstanceCheckedAccessors(false);
17841}
17842
17843
17844THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17845 v8::internal::FLAG_allow_natives_syntax = true;
17846 v8::HandleScope scope;
17847 LocalContext context;
17848
17849 Local<FunctionTemplate> templ = FunctionTemplate::New();
17850 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17851 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17852 inst->SetAccessor(v8_str("foo"),
17853 InstanceCheckedGetter, InstanceCheckedSetter,
17854 Handle<Value>(),
17855 v8::DEFAULT,
17856 v8::None,
17857 v8::AccessorSignature::New(templ));
17858 context->Global()->Set(v8_str("f"), templ->GetFunction());
17859
17860 printf("Testing positive ...\n");
17861 CompileRun("var obj = new f();");
17862 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17863 CheckInstanceCheckedAccessors(true);
17864
17865 printf("Testing negative ...\n");
17866 CompileRun("var obj = {};"
17867 "obj.__proto__ = new f();");
17868 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17869 CheckInstanceCheckedAccessors(false);
17870}
17871
17872
17873THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17874 v8::internal::FLAG_allow_natives_syntax = true;
17875 v8::HandleScope scope;
17876 LocalContext context;
17877
17878 Local<FunctionTemplate> templ = FunctionTemplate::New();
17879 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17880 proto->SetAccessor(v8_str("foo"),
17881 InstanceCheckedGetter, InstanceCheckedSetter,
17882 Handle<Value>(),
17883 v8::DEFAULT,
17884 v8::None,
17885 v8::AccessorSignature::New(templ));
17886 context->Global()->Set(v8_str("f"), templ->GetFunction());
17887
17888 printf("Testing positive ...\n");
17889 CompileRun("var obj = new f();");
17890 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17891 CheckInstanceCheckedAccessors(true);
17892
17893 printf("Testing negative ...\n");
17894 CompileRun("var obj = {};"
17895 "obj.__proto__ = new f();");
17896 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17897 CheckInstanceCheckedAccessors(false);
17898
17899 printf("Testing positive with modified prototype chain ...\n");
17900 CompileRun("var obj = new f();"
17901 "var pro = {};"
17902 "pro.__proto__ = obj.__proto__;"
17903 "obj.__proto__ = pro;");
17904 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17905 CheckInstanceCheckedAccessors(true);
17906}
17907
17908
17909TEST(TryFinallyMessage) {
17910 v8::HandleScope scope;
17911 LocalContext context;
17912 {
17913 // Test that the original error message is not lost if there is a
17914 // recursive call into Javascript is done in the finally block, e.g. to
17915 // initialize an IC. (crbug.com/129171)
17916 TryCatch try_catch;
17917 const char* trigger_ic =
17918 "try { \n"
17919 " throw new Error('test'); \n"
17920 "} finally { \n"
17921 " var x = 0; \n"
17922 " x++; \n" // Trigger an IC initialization here.
17923 "} \n";
17924 CompileRun(trigger_ic);
17925 CHECK(try_catch.HasCaught());
17926 Local<Message> message = try_catch.Message();
17927 CHECK(!message.IsEmpty());
17928 CHECK_EQ(2, message->GetLineNumber());
17929 }
17930
17931 {
17932 // Test that the original exception message is indeed overwritten if
17933 // a new error is thrown in the finally block.
17934 TryCatch try_catch;
17935 const char* throw_again =
17936 "try { \n"
17937 " throw new Error('test'); \n"
17938 "} finally { \n"
17939 " var x = 0; \n"
17940 " x++; \n"
17941 " throw new Error('again'); \n" // This is the new uncaught error.
17942 "} \n";
17943 CompileRun(throw_again);
17944 CHECK(try_catch.HasCaught());
17945 Local<Message> message = try_catch.Message();
17946 CHECK(!message.IsEmpty());
17947 CHECK_EQ(6, message->GetLineNumber());
17948 }
17949}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017950
17951
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017952static void Helper137002(bool do_store,
17953 bool polymorphic,
17954 bool remove_accessor,
17955 bool interceptor) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017956 LocalContext context;
17957 Local<ObjectTemplate> templ = ObjectTemplate::New();
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017958 if (interceptor) {
17959 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17960 } else {
17961 templ->SetAccessor(v8_str("foo"),
17962 GetterWhichReturns42,
17963 SetterWhichSetsYOnThisTo23);
17964 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017965 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17966
17967 // Turn monomorphic on slow object with native accessor, then turn
17968 // polymorphic, finally optimize to create negative lookup and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017969 CompileRun(do_store ?
17970 "function f(x) { x.foo = void 0; }" :
17971 "function f(x) { return x.foo; }");
17972 CompileRun("obj.y = void 0;");
17973 if (!interceptor) {
17974 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
17975 }
17976 CompileRun("obj.__proto__ = null;"
17977 "f(obj); f(obj); f(obj);");
17978 if (polymorphic) {
17979 CompileRun("f({});");
17980 }
17981 CompileRun("obj.y = void 0;"
17982 "%OptimizeFunctionOnNextCall(f);");
17983 if (remove_accessor) {
17984 CompileRun("delete obj.foo;");
17985 }
17986 CompileRun("var result = f(obj);");
17987 if (do_store) {
17988 CompileRun("result = obj.y;");
17989 }
17990 if (remove_accessor && !interceptor) {
17991 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17992 } else {
17993 CHECK_EQ(do_store ? 23 : 42,
17994 context->Global()->Get(v8_str("result"))->Int32Value());
17995 }
17996}
17997
17998
17999THREADED_TEST(Regress137002a) {
18000 i::FLAG_allow_natives_syntax = true;
18001 i::FLAG_compilation_cache = false;
18002 v8::HandleScope scope;
18003 for (int i = 0; i < 16; i++) {
18004 Helper137002(i & 8, i & 4, i & 2, i & 1);
18005 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018006}
18007
18008
18009THREADED_TEST(Regress137002b) {
18010 i::FLAG_allow_natives_syntax = true;
18011 v8::HandleScope scope;
18012 LocalContext context;
18013 Local<ObjectTemplate> templ = ObjectTemplate::New();
18014 templ->SetAccessor(v8_str("foo"),
18015 GetterWhichReturns42,
18016 SetterWhichSetsYOnThisTo23);
18017 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18018
18019 // Turn monomorphic on slow object with native accessor, then just
18020 // delete the property and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018021 CompileRun("function load(x) { return x.foo; }"
18022 "function store(x) { x.foo = void 0; }"
18023 "function keyed_load(x, key) { return x[key]; }"
18024 // Second version of function has a different source (add void 0)
18025 // so that it does not share code with the first version. This
18026 // ensures that the ICs are monomorphic.
18027 "function load2(x) { void 0; return x.foo; }"
18028 "function store2(x) { void 0; x.foo = void 0; }"
18029 "function keyed_load2(x, key) { void 0; return x[key]; }"
18030
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018031 "obj.y = void 0;"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018032 "obj.__proto__ = null;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018033 "var subobj = {};"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018034 "subobj.y = void 0;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018035 "subobj.__proto__ = obj;"
18036 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
18037
18038 // Make the ICs monomorphic.
18039 "load(obj); load(obj);"
18040 "load2(subobj); load2(subobj);"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018041 "store(obj); store(obj);"
18042 "store2(subobj); store2(subobj);"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018043 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
18044 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
18045
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018046 // Actually test the shiny new ICs and better not crash. This
18047 // serves as a regression test for issue 142088 as well.
18048 "load(obj);"
18049 "load2(subobj);"
18050 "store(obj);"
18051 "store2(subobj);"
18052 "keyed_load(obj, 'foo');"
18053 "keyed_load2(subobj, 'foo');"
18054
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018055 // Delete the accessor. It better not be called any more now.
18056 "delete obj.foo;"
18057 "obj.y = void 0;"
18058 "subobj.y = void 0;"
18059
18060 "var load_result = load(obj);"
18061 "var load_result2 = load2(subobj);"
18062 "var keyed_load_result = keyed_load(obj, 'foo');"
18063 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
18064 "store(obj);"
18065 "store2(subobj);"
18066 "var y_from_obj = obj.y;"
18067 "var y_from_subobj = subobj.y;");
18068 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
18069 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
18070 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
18071 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
18072 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
18073 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018074}
verwaest@chromium.org753aee42012-07-17 16:15:42 +000018075
18076
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018077THREADED_TEST(Regress142088) {
18078 i::FLAG_allow_natives_syntax = true;
18079 v8::HandleScope scope;
18080 LocalContext context;
18081 Local<ObjectTemplate> templ = ObjectTemplate::New();
18082 templ->SetAccessor(v8_str("foo"),
18083 GetterWhichReturns42,
18084 SetterWhichSetsYOnThisTo23);
18085 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18086
18087 CompileRun("function load(x) { return x.foo; }"
18088 "var o = Object.create(obj);"
18089 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
18090 "load(o); load(o); load(o); load(o);");
18091}
18092
18093
verwaest@chromium.org753aee42012-07-17 16:15:42 +000018094THREADED_TEST(Regress137496) {
18095 i::FLAG_expose_gc = true;
18096 v8::HandleScope scope;
18097 LocalContext context;
18098
18099 // Compile a try-finally clause where the finally block causes a GC
18100 // while there still is a message pending for external reporting.
18101 TryCatch try_catch;
18102 try_catch.SetVerbose(true);
18103 CompileRun("try { throw new Error(); } finally { gc(); }");
18104 CHECK(try_catch.HasCaught());
18105}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018106
18107
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000018108THREADED_TEST(Regress149912) {
18109 v8::HandleScope scope;
18110 LocalContext context;
18111 Handle<FunctionTemplate> templ = FunctionTemplate::New();
18112 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
18113 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
18114 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
18115}
18116
18117
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000018118THREADED_TEST(Regress157124) {
18119 v8::HandleScope scope;
18120 LocalContext context;
18121 Local<ObjectTemplate> templ = ObjectTemplate::New();
18122 Local<Object> obj = templ->NewInstance();
18123 obj->GetIdentityHash();
18124 obj->DeleteHiddenValue(v8_str("Bug"));
18125}
18126
18127
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018128#ifndef WIN32
18129class ThreadInterruptTest {
18130 public:
18131 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
18132 ~ThreadInterruptTest() { delete sem_; }
18133
18134 void RunTest() {
18135 sem_ = i::OS::CreateSemaphore(0);
18136
18137 InterruptThread i_thread(this);
18138 i_thread.Start();
18139
18140 sem_->Wait();
18141 CHECK_EQ(kExpectedValue, sem_value_);
18142 }
18143
18144 private:
18145 static const int kExpectedValue = 1;
18146
18147 class InterruptThread : public i::Thread {
18148 public:
18149 explicit InterruptThread(ThreadInterruptTest* test)
18150 : Thread("InterruptThread"), test_(test) {}
18151
18152 virtual void Run() {
18153 struct sigaction action;
18154
18155 // Ensure that we'll enter waiting condition
18156 i::OS::Sleep(100);
18157
18158 // Setup signal handler
18159 memset(&action, 0, sizeof(action));
18160 action.sa_handler = SignalHandler;
18161 sigaction(SIGCHLD, &action, NULL);
18162
18163 // Send signal
18164 kill(getpid(), SIGCHLD);
18165
18166 // Ensure that if wait has returned because of error
18167 i::OS::Sleep(100);
18168
18169 // Set value and signal semaphore
18170 test_->sem_value_ = 1;
18171 test_->sem_->Signal();
18172 }
18173
18174 static void SignalHandler(int signal) {
18175 }
18176
18177 private:
18178 ThreadInterruptTest* test_;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018179 };
18180
18181 i::Semaphore* sem_;
18182 volatile int sem_value_;
18183};
18184
18185
18186THREADED_TEST(SemaphoreInterruption) {
18187 ThreadInterruptTest().RunTest();
18188}
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000018189
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018190#endif // WIN32