blob: 028f82f3dc61560f31694c9535b2392dc4179b15 [file] [log] [blame]
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// 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
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "api.h"
33#include "cctest.h"
34#include "frames-inl.h"
35#include "string-stream.h"
36
37using ::v8::ObjectTemplate;
38using ::v8::Value;
39using ::v8::Context;
40using ::v8::Local;
41using ::v8::String;
42using ::v8::Script;
43using ::v8::Function;
44using ::v8::AccessorInfo;
45using ::v8::Extension;
46
47namespace i = ::v8::internal;
48
49static v8::Handle<Value> handle_property(Local<String> name,
50 const AccessorInfo&) {
51 ApiTestFuzzer::Fuzz();
52 return v8_num(900);
53}
54
55
56THREADED_TEST(PropertyHandler) {
57 v8::HandleScope scope;
58 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
59 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
60 LocalContext env;
61 Local<Function> fun = fun_templ->GetFunction();
62 env->Global()->Set(v8_str("Fun"), fun);
63 Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
64 CHECK_EQ(900, getter->Run()->Int32Value());
65 Local<Script> setter = v8_compile("obj.foo = 901;");
66 CHECK_EQ(901, setter->Run()->Int32Value());
67}
68
69
70static v8::Handle<Value> GetIntValue(Local<String> property,
71 const AccessorInfo& info) {
72 ApiTestFuzzer::Fuzz();
73 int* value =
74 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
75 return v8_num(*value);
76}
77
78
79static void SetIntValue(Local<String> property,
80 Local<Value> value,
81 const AccessorInfo& info) {
82 int* field =
83 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
84 *field = value->Int32Value();
85}
86
87int foo, bar, baz;
88
89THREADED_TEST(GlobalVariableAccess) {
90 foo = 0;
91 bar = -4;
92 baz = 10;
93 v8::HandleScope scope;
94 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
95 templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
96 GetIntValue,
97 SetIntValue,
98 v8::External::New(&foo));
99 templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
100 GetIntValue,
101 SetIntValue,
102 v8::External::New(&bar));
103 templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
104 GetIntValue,
105 SetIntValue,
106 v8::External::New(&baz));
107 LocalContext env(0, templ->InstanceTemplate());
108 v8_compile("foo = (++bar) + baz")->Run();
109 CHECK_EQ(bar, -3);
110 CHECK_EQ(foo, 7);
111}
112
113
114static int x_register = 0;
115static v8::Handle<v8::Object> x_receiver;
116static v8::Handle<v8::Object> x_holder;
117
118
119static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
120 ApiTestFuzzer::Fuzz();
121 CHECK_EQ(x_receiver, info.This());
122 CHECK_EQ(x_holder, info.Holder());
123 return v8_num(x_register);
124}
125
126
127static void XSetter(Local<String> name,
128 Local<Value> value,
129 const AccessorInfo& info) {
130 CHECK_EQ(x_holder, info.This());
131 CHECK_EQ(x_holder, info.Holder());
132 x_register = value->Int32Value();
133}
134
135
136THREADED_TEST(AccessorIC) {
137 v8::HandleScope scope;
138 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
139 obj->SetAccessor(v8_str("x"), XGetter, XSetter);
140 LocalContext context;
141 x_holder = obj->NewInstance();
142 context->Global()->Set(v8_str("holder"), x_holder);
143 x_receiver = v8::Object::New();
144 context->Global()->Set(v8_str("obj"), x_receiver);
145 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
146 "obj.__proto__ = holder;"
147 "var result = [];"
148 "for (var i = 0; i < 10; i++) {"
149 " holder.x = i;"
150 " result.push(obj.x);"
151 "}"
152 "result"));
153 CHECK_EQ(10, array->Length());
154 for (int i = 0; i < 10; i++) {
155 v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
156 CHECK_EQ(v8::Integer::New(i), entry);
157 }
158}
159
160
161static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
162 Local<String> name,
163 const AccessorInfo& info) {
164 ApiTestFuzzer::Fuzz();
165 return v8::True();
166}
167
168
169THREADED_TEST(AccessorProhibitsOverwriting) {
170 v8::HandleScope scope;
171 LocalContext context;
172 Local<ObjectTemplate> templ = ObjectTemplate::New();
173 templ->SetAccessor(v8_str("x"),
174 AccessorProhibitsOverwritingGetter,
175 0,
176 v8::Handle<Value>(),
177 v8::PROHIBITS_OVERWRITING,
178 v8::ReadOnly);
179 Local<v8::Object> instance = templ->NewInstance();
180 context->Global()->Set(v8_str("obj"), instance);
181 Local<Value> value = CompileRun(
182 "obj.__defineGetter__('x', function() { return false; });"
183 "obj.x");
184 CHECK(value->BooleanValue());
185 value = CompileRun(
186 "var setter_called = false;"
187 "obj.__defineSetter__('x', function() { setter_called = true; });"
188 "obj.x = 42;"
189 "setter_called");
190 CHECK(!value->BooleanValue());
191 value = CompileRun(
192 "obj2 = {};"
193 "obj2.__proto__ = obj;"
194 "obj2.__defineGetter__('x', function() { return false; });"
195 "obj2.x");
196 CHECK(value->BooleanValue());
197 value = CompileRun(
198 "var setter_called = false;"
199 "obj2 = {};"
200 "obj2.__proto__ = obj;"
201 "obj2.__defineSetter__('x', function() { setter_called = true; });"
202 "obj2.x = 42;"
203 "setter_called");
204 CHECK(!value->BooleanValue());
205}
206
207
208template <int C>
209static v8::Handle<Value> HandleAllocatingGetter(Local<String> name,
210 const AccessorInfo& info) {
211 ApiTestFuzzer::Fuzz();
212 for (int i = 0; i < C; i++)
213 v8::String::New("foo");
214 return v8::String::New("foo");
215}
216
217
218THREADED_TEST(HandleScopePop) {
219 v8::HandleScope scope;
220 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
221 obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
222 obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
223 LocalContext context;
224 v8::Handle<v8::Object> inst = obj->NewInstance();
225 context->Global()->Set(v8::String::New("obj"), inst);
226 int count_before = i::HandleScope::NumberOfHandles();
227 {
228 v8::HandleScope scope;
229 CompileRun(
230 "for (var i = 0; i < 1000; i++) {"
231 " obj.one;"
232 " obj.many;"
233 "}");
234 }
235 int count_after = i::HandleScope::NumberOfHandles();
236 CHECK_EQ(count_before, count_after);
237}
238
239static v8::Handle<Value> CheckAccessorArgsCorrect(Local<String> name,
240 const AccessorInfo& info) {
241 CHECK(info.This() == info.Holder());
242 CHECK(info.Data()->Equals(v8::String::New("data")));
243 ApiTestFuzzer::Fuzz();
244 CHECK(info.This() == info.Holder());
245 CHECK(info.Data()->Equals(v8::String::New("data")));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000246 HEAP->CollectAllGarbage(true);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000247 CHECK(info.This() == info.Holder());
248 CHECK(info.Data()->Equals(v8::String::New("data")));
249 return v8::Integer::New(17);
250}
251
252THREADED_TEST(DirectCall) {
253 v8::HandleScope scope;
254 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
255 obj->SetAccessor(v8_str("xxx"),
256 CheckAccessorArgsCorrect,
257 NULL,
258 v8::String::New("data"));
259 LocalContext context;
260 v8::Handle<v8::Object> inst = obj->NewInstance();
261 context->Global()->Set(v8::String::New("obj"), inst);
262 Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
263 for (int i = 0; i < 10; i++) {
264 Local<Value> result = scr->Run();
265 CHECK(!result.IsEmpty());
266 CHECK_EQ(17, result->Int32Value());
267 }
268}
269
270static v8::Handle<Value> EmptyGetter(Local<String> name,
271 const AccessorInfo& info) {
272 CheckAccessorArgsCorrect(name, info);
273 ApiTestFuzzer::Fuzz();
274 CheckAccessorArgsCorrect(name, info);
275 return v8::Handle<v8::Value>();
276}
277
278THREADED_TEST(EmptyResult) {
279 v8::HandleScope scope;
280 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
281 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data"));
282 LocalContext context;
283 v8::Handle<v8::Object> inst = obj->NewInstance();
284 context->Global()->Set(v8::String::New("obj"), inst);
285 Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
286 for (int i = 0; i < 10; i++) {
287 Local<Value> result = scr->Run();
288 CHECK(result == v8::Undefined());
289 }
290}
291
292
293THREADED_TEST(NoReuseRegress) {
294 // Check that the IC generated for the one test doesn't get reused
295 // for the other.
296 v8::HandleScope scope;
297 {
298 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
299 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data"));
300 LocalContext context;
301 v8::Handle<v8::Object> inst = obj->NewInstance();
302 context->Global()->Set(v8::String::New("obj"), inst);
303 Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
304 for (int i = 0; i < 2; i++) {
305 Local<Value> result = scr->Run();
306 CHECK(result == v8::Undefined());
307 }
308 }
309 {
310 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
311 obj->SetAccessor(v8_str("xxx"),
312 CheckAccessorArgsCorrect,
313 NULL,
314 v8::String::New("data"));
315 LocalContext context;
316 v8::Handle<v8::Object> inst = obj->NewInstance();
317 context->Global()->Set(v8::String::New("obj"), inst);
318 Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
319 for (int i = 0; i < 10; i++) {
320 Local<Value> result = scr->Run();
321 CHECK(!result.IsEmpty());
322 CHECK_EQ(17, result->Int32Value());
323 }
324 }
325}
326
327static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
328 const AccessorInfo& info) {
329 ApiTestFuzzer::Fuzz();
330 return v8::ThrowException(v8_str("g"));
331}
332
333
334static void ThrowingSetAccessor(Local<String> name,
335 Local<Value> value,
336 const AccessorInfo& info) {
337 v8::ThrowException(value);
338}
339
340
341THREADED_TEST(Regress1054726) {
342 v8::HandleScope scope;
343 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
344 obj->SetAccessor(v8_str("x"),
345 ThrowingGetAccessor,
346 ThrowingSetAccessor,
347 Local<Value>());
348
349 LocalContext env;
350 env->Global()->Set(v8_str("obj"), obj->NewInstance());
351
352 // Use the throwing property setter/getter in a loop to force
353 // the accessor ICs to be initialized.
354 v8::Handle<Value> result;
355 result = Script::Compile(v8_str(
356 "var result = '';"
357 "for (var i = 0; i < 5; i++) {"
358 " try { obj.x; } catch (e) { result += e; }"
359 "}; result"))->Run();
360 CHECK_EQ(v8_str("ggggg"), result);
361
362 result = Script::Compile(String::New(
363 "var result = '';"
364 "for (var i = 0; i < 5; i++) {"
365 " try { obj.x = i; } catch (e) { result += e; }"
366 "}; result"))->Run();
367 CHECK_EQ(v8_str("01234"), result);
368}
369
370
371static v8::Handle<Value> AllocGetter(Local<String> name,
372 const AccessorInfo& info) {
373 ApiTestFuzzer::Fuzz();
374 return v8::Array::New(1000);
375}
376
377
378THREADED_TEST(Gc) {
379 v8::HandleScope scope;
380 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
381 obj->SetAccessor(v8_str("xxx"), AllocGetter);
382 LocalContext env;
383 env->Global()->Set(v8_str("obj"), obj->NewInstance());
384 Script::Compile(String::New(
385 "var last = [];"
386 "for (var i = 0; i < 2048; i++) {"
387 " var result = obj.xxx;"
388 " result[0] = last;"
389 " last = result;"
390 "}"))->Run();
391}
392
393
394static v8::Handle<Value> StackCheck(Local<String> name,
395 const AccessorInfo& info) {
396 i::StackFrameIterator iter;
397 for (int i = 0; !iter.done(); i++) {
398 i::StackFrame* frame = iter.frame();
399 CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000400 i::Code* code = frame->LookupCode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 CHECK(code->IsCode());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000402 i::Address pc = frame->pc();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000403 CHECK(code->contains(pc));
404 iter.Advance();
405 }
406 return v8::Undefined();
407}
408
409
410THREADED_TEST(StackIteration) {
411 v8::HandleScope scope;
412 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
413 i::StringStream::ClearMentionedObjectCache();
414 obj->SetAccessor(v8_str("xxx"), StackCheck);
415 LocalContext env;
416 env->Global()->Set(v8_str("obj"), obj->NewInstance());
417 Script::Compile(String::New(
418 "function foo() {"
419 " return obj.xxx;"
420 "}"
421 "for (var i = 0; i < 100; i++) {"
422 " foo();"
423 "}"))->Run();
424}
425
426
427static v8::Handle<Value> AllocateHandles(Local<String> name,
428 const AccessorInfo& info) {
429 for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
430 v8::Local<v8::Value>::New(name);
431 }
432 return v8::Integer::New(100);
433}
434
435
436THREADED_TEST(HandleScopeSegment) {
437 // Check that we can return values past popping of handle scope
438 // segments.
439 v8::HandleScope scope;
440 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
441 obj->SetAccessor(v8_str("xxx"), AllocateHandles);
442 LocalContext env;
443 env->Global()->Set(v8_str("obj"), obj->NewInstance());
444 v8::Handle<v8::Value> result = Script::Compile(String::New(
445 "var result;"
446 "for (var i = 0; i < 4; i++)"
447 " result = obj.xxx;"
448 "result;"))->Run();
449 CHECK_EQ(100, result->Int32Value());
450}