1 // 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
37 using ::v8::ObjectTemplate;
38 using ::v8::Value;
39 using ::v8::Context;
40 using ::v8::Local;
41 using ::v8::String;
42 using ::v8::Script;
43 using ::v8::Function;
44 using ::v8::AccessorInfo;
45 using ::v8::Extension;
46
47 namespace i = ::v8::internal;
48
handle_property(Local<String> name,const AccessorInfo &)49 static v8::Handle<Value> handle_property(Local<String> name,
50 const AccessorInfo&) {
51 ApiTestFuzzer::Fuzz();
52 return v8_num(900);
53 }
54
55
THREADED_TEST(PropertyHandler)56 THREADED_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
GetIntValue(Local<String> property,const AccessorInfo & info)70 static 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
SetIntValue(Local<String> property,Local<Value> value,const AccessorInfo & info)79 static 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
87 int foo, bar, baz;
88
THREADED_TEST(GlobalVariableAccess)89 THREADED_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
114 static int x_register = 0;
115 static v8::Handle<v8::Object> x_receiver;
116 static v8::Handle<v8::Object> x_holder;
117
118
XGetter(Local<String> name,const AccessorInfo & info)119 static 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
XSetter(Local<String> name,Local<Value> value,const AccessorInfo & info)127 static 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
THREADED_TEST(AccessorIC)136 THREADED_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
AccessorProhibitsOverwritingGetter(Local<String> name,const AccessorInfo & info)161 static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
162 Local<String> name,
163 const AccessorInfo& info) {
164 ApiTestFuzzer::Fuzz();
165 return v8::True();
166 }
167
168
THREADED_TEST(AccessorProhibitsOverwriting)169 THREADED_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
208 template <int C>
HandleAllocatingGetter(Local<String> name,const AccessorInfo & info)209 static 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
THREADED_TEST(HandleScopePop)218 THREADED_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
CheckAccessorArgsCorrect(Local<String> name,const AccessorInfo & info)239 static 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")));
246 i::Heap::CollectAllGarbage(true);
247 CHECK(info.This() == info.Holder());
248 CHECK(info.Data()->Equals(v8::String::New("data")));
249 return v8::Integer::New(17);
250 }
251
THREADED_TEST(DirectCall)252 THREADED_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
EmptyGetter(Local<String> name,const AccessorInfo & info)270 static 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
THREADED_TEST(EmptyResult)278 THREADED_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
THREADED_TEST(NoReuseRegress)293 THREADED_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
ThrowingGetAccessor(Local<String> name,const AccessorInfo & info)327 static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
328 const AccessorInfo& info) {
329 ApiTestFuzzer::Fuzz();
330 return v8::ThrowException(v8_str("g"));
331 }
332
333
ThrowingSetAccessor(Local<String> name,Local<Value> value,const AccessorInfo & info)334 static void ThrowingSetAccessor(Local<String> name,
335 Local<Value> value,
336 const AccessorInfo& info) {
337 v8::ThrowException(value);
338 }
339
340
THREADED_TEST(Regress1054726)341 THREADED_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
AllocGetter(Local<String> name,const AccessorInfo & info)371 static v8::Handle<Value> AllocGetter(Local<String> name,
372 const AccessorInfo& info) {
373 ApiTestFuzzer::Fuzz();
374 return v8::Array::New(1000);
375 }
376
377
THREADED_TEST(Gc)378 THREADED_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
StackCheck(Local<String> name,const AccessorInfo & info)394 static 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));
400 CHECK(frame->code()->IsCode());
401 i::Address pc = frame->pc();
402 i::Code* code = frame->code();
403 CHECK(code->contains(pc));
404 iter.Advance();
405 }
406 return v8::Undefined();
407 }
408
409
THREADED_TEST(StackIteration)410 THREADED_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
AllocateHandles(Local<String> name,const AccessorInfo & info)427 static 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
THREADED_TEST(HandleScopeSegment)436 THREADED_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 }
451