• 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 
handle_property(Local<String> name,const AccessorInfo &)47 static v8::Handle<Value> handle_property(Local<String> name,
48                                          const AccessorInfo&) {
49   ApiTestFuzzer::Fuzz();
50   return v8_num(900);
51 }
52 
53 
THREADED_TEST(PropertyHandler)54 THREADED_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 
GetIntValue(Local<String> property,const AccessorInfo & info)68 static 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 
SetIntValue(Local<String> property,Local<Value> value,const AccessorInfo & info)77 static 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 
85 int foo, bar, baz;
86 
THREADED_TEST(GlobalVariableAccess)87 THREADED_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 
112 static int x_register = 0;
113 static v8::Handle<v8::Object> x_receiver;
114 static v8::Handle<v8::Object> x_holder;
115 
116 
XGetter(Local<String> name,const AccessorInfo & info)117 static 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 
XSetter(Local<String> name,Local<Value> value,const AccessorInfo & info)125 static 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 
THREADED_TEST(AccessorIC)134 THREADED_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 
AccessorProhibitsOverwritingGetter(Local<String> name,const AccessorInfo & info)159 static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
160     Local<String> name,
161     const AccessorInfo& info) {
162   ApiTestFuzzer::Fuzz();
163   return v8::True();
164 }
165 
166 
THREADED_TEST(AccessorProhibitsOverwriting)167 THREADED_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 
206 template <int C>
HandleAllocatingGetter(Local<String> name,const AccessorInfo & info)207 static 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 
THREADED_TEST(HandleScopePop)216 THREADED_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 
CheckAccessorArgsCorrect(Local<String> name,const AccessorInfo & info)237 static 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")));
244   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
245   CHECK(info.This() == info.Holder());
246   CHECK(info.Data()->Equals(v8::String::New("data")));
247   return v8::Integer::New(17);
248 }
249 
THREADED_TEST(DirectCall)250 THREADED_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 
EmptyGetter(Local<String> name,const AccessorInfo & info)268 static 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 
THREADED_TEST(EmptyResult)276 THREADED_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 
THREADED_TEST(NoReuseRegress)291 THREADED_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 
ThrowingGetAccessor(Local<String> name,const AccessorInfo & info)325 static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
326                                              const AccessorInfo& info) {
327   ApiTestFuzzer::Fuzz();
328   return v8::ThrowException(v8_str("g"));
329 }
330 
331 
ThrowingSetAccessor(Local<String> name,Local<Value> value,const AccessorInfo & info)332 static void ThrowingSetAccessor(Local<String> name,
333                                 Local<Value> value,
334                                 const AccessorInfo& info) {
335   v8::ThrowException(value);
336 }
337 
338 
THREADED_TEST(Regress1054726)339 THREADED_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 
AllocGetter(Local<String> name,const AccessorInfo & info)369 static v8::Handle<Value> AllocGetter(Local<String> name,
370                                      const AccessorInfo& info) {
371   ApiTestFuzzer::Fuzz();
372   return v8::Array::New(1000);
373 }
374 
375 
THREADED_TEST(Gc)376 THREADED_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 
StackCheck(Local<String> name,const AccessorInfo & info)392 static 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));
398     i::Code* code = frame->LookupCode();
399     CHECK(code->IsCode());
400     i::Address pc = frame->pc();
401     CHECK(code->contains(pc));
402     iter.Advance();
403   }
404   return v8::Undefined();
405 }
406 
407 
THREADED_TEST(StackIteration)408 THREADED_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 
AllocateHandles(Local<String> name,const AccessorInfo & info)425 static 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 
THREADED_TEST(HandleScopeSegment)434 THREADED_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 }
449