Home | History | Annotate | Download | only in cctest
      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 
     49 static v8::Handle<Value> handle_property(Local<String> name,
     50                                          const AccessorInfo&) {
     51   ApiTestFuzzer::Fuzz();
     52   return v8_num(900);
     53 }
     54 
     55 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    161 static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
    162     Local<String> name,
    163     const AccessorInfo& info) {
    164   ApiTestFuzzer::Fuzz();
    165   return v8::True();
    166 }
    167 
    168 
    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>
    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 
    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 
    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   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 
    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 
    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 
    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 
    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 
    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 
    334 static void ThrowingSetAccessor(Local<String> name,
    335                                 Local<Value> value,
    336                                 const AccessorInfo& info) {
    337   v8::ThrowException(value);
    338 }
    339 
    340 
    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 
    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 
    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 
    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     i::Code* code = frame->LookupCode();
    401     CHECK(code->IsCode());
    402     i::Address pc = frame->pc();
    403     CHECK(code->contains(pc));
    404     iter.Advance();
    405   }
    406   return v8::Undefined();
    407 }
    408 
    409 
    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 
    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 
    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