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