• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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