Home | History | Annotate | Download | only in cctest
      1 // Copyright 2012 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 static void handle_property(Local<String> name,
     48                             const v8::PropertyCallbackInfo<v8::Value>& info) {
     49   ApiTestFuzzer::Fuzz();
     50   info.GetReturnValue().Set(v8_num(900));
     51 }
     52 
     53 
     54 THREADED_TEST(PropertyHandler) {
     55   LocalContext env;
     56   v8::HandleScope scope(env->GetIsolate());
     57   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
     58   fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
     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 
     68 static void GetIntValue(Local<String> property,
     69                         const v8::PropertyCallbackInfo<v8::Value>& info) {
     70   ApiTestFuzzer::Fuzz();
     71   int* value =
     72       static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
     73   info.GetReturnValue().Set(v8_num(*value));
     74 }
     75 
     76 
     77 static void SetIntValue(Local<String> property,
     78                         Local<Value> value,
     79                         const v8::PropertyCallbackInfo<void>& 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 
     87 THREADED_TEST(GlobalVariableAccess) {
     88   foo = 0;
     89   bar = -4;
     90   baz = 10;
     91   v8::HandleScope scope(v8::Isolate::GetCurrent());
     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 
    117 static void XGetter(Local<String> name,
    118                     const v8::PropertyCallbackInfo<v8::Value>& info) {
    119   ApiTestFuzzer::Fuzz();
    120   v8::Isolate* isolate = v8::Isolate::GetCurrent();
    121   CHECK_EQ(isolate, info.GetIsolate());
    122   CHECK_EQ(x_receiver, info.This());
    123   CHECK_EQ(x_holder, info.Holder());
    124   info.GetReturnValue().Set(v8_num(x_register));
    125 }
    126 
    127 
    128 static void XSetter(Local<String> name,
    129                     Local<Value> value,
    130                     const v8::PropertyCallbackInfo<void>& info) {
    131   v8::Isolate* isolate = v8::Isolate::GetCurrent();
    132   CHECK_EQ(isolate, info.GetIsolate());
    133   CHECK_EQ(x_holder, info.This());
    134   CHECK_EQ(x_holder, info.Holder());
    135   x_register = value->Int32Value();
    136 }
    137 
    138 
    139 THREADED_TEST(AccessorIC) {
    140   LocalContext context;
    141   v8::HandleScope scope(context->GetIsolate());
    142   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    143   obj->SetAccessor(v8_str("x"), XGetter, XSetter);
    144   x_holder = obj->NewInstance();
    145   context->Global()->Set(v8_str("holder"), x_holder);
    146   x_receiver = v8::Object::New();
    147   context->Global()->Set(v8_str("obj"), x_receiver);
    148   v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
    149     "obj.__proto__ = holder;"
    150     "var result = [];"
    151     "for (var i = 0; i < 10; i++) {"
    152     "  holder.x = i;"
    153     "  result.push(obj.x);"
    154     "}"
    155     "result"));
    156   CHECK_EQ(10, array->Length());
    157   for (int i = 0; i < 10; i++) {
    158     v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
    159     CHECK_EQ(v8::Integer::New(i), entry);
    160   }
    161 }
    162 
    163 
    164 static void AccessorProhibitsOverwritingGetter(
    165     Local<String> name,
    166     const v8::PropertyCallbackInfo<v8::Value>& info) {
    167   ApiTestFuzzer::Fuzz();
    168   info.GetReturnValue().Set(true);
    169 }
    170 
    171 
    172 THREADED_TEST(AccessorProhibitsOverwriting) {
    173   LocalContext context;
    174   v8::HandleScope scope(context->GetIsolate());
    175   Local<ObjectTemplate> templ = ObjectTemplate::New();
    176   templ->SetAccessor(v8_str("x"),
    177                      AccessorProhibitsOverwritingGetter,
    178                      0,
    179                      v8::Handle<Value>(),
    180                      v8::PROHIBITS_OVERWRITING,
    181                      v8::ReadOnly);
    182   Local<v8::Object> instance = templ->NewInstance();
    183   context->Global()->Set(v8_str("obj"), instance);
    184   Local<Value> value = CompileRun(
    185       "obj.__defineGetter__('x', function() { return false; });"
    186       "obj.x");
    187   CHECK(value->BooleanValue());
    188   value = CompileRun(
    189       "var setter_called = false;"
    190       "obj.__defineSetter__('x', function() { setter_called = true; });"
    191       "obj.x = 42;"
    192       "setter_called");
    193   CHECK(!value->BooleanValue());
    194   value = CompileRun(
    195       "obj2 = {};"
    196       "obj2.__proto__ = obj;"
    197       "obj2.__defineGetter__('x', function() { return false; });"
    198       "obj2.x");
    199   CHECK(value->BooleanValue());
    200   value = CompileRun(
    201       "var setter_called = false;"
    202       "obj2 = {};"
    203       "obj2.__proto__ = obj;"
    204       "obj2.__defineSetter__('x', function() { setter_called = true; });"
    205       "obj2.x = 42;"
    206       "setter_called");
    207   CHECK(!value->BooleanValue());
    208 }
    209 
    210 
    211 template <int C>
    212 static void HandleAllocatingGetter(
    213     Local<String> name,
    214     const v8::PropertyCallbackInfo<v8::Value>& info) {
    215   ApiTestFuzzer::Fuzz();
    216   for (int i = 0; i < C; i++)
    217     v8::String::New("foo");
    218   info.GetReturnValue().Set(v8::String::New("foo"));
    219 }
    220 
    221 
    222 THREADED_TEST(HandleScopePop) {
    223   LocalContext context;
    224   v8::HandleScope scope(context->GetIsolate());
    225   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    226   obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
    227   obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
    228   v8::Handle<v8::Object> inst = obj->NewInstance();
    229   context->Global()->Set(v8::String::New("obj"), inst);
    230   i::Isolate* isolate = i::Isolate::Current();
    231   int count_before = i::HandleScope::NumberOfHandles(isolate);
    232   {
    233     v8::HandleScope scope(context->GetIsolate());
    234     CompileRun(
    235         "for (var i = 0; i < 1000; i++) {"
    236         "  obj.one;"
    237         "  obj.many;"
    238         "}");
    239   }
    240   int count_after = i::HandleScope::NumberOfHandles(isolate);
    241   CHECK_EQ(count_before, count_after);
    242 }
    243 
    244 static void CheckAccessorArgsCorrect(
    245     Local<String> name,
    246     const v8::PropertyCallbackInfo<v8::Value>& info) {
    247   CHECK(info.GetIsolate() == v8::Isolate::GetCurrent());
    248   CHECK(info.This() == info.Holder());
    249   CHECK(info.Data()->Equals(v8::String::New("data")));
    250   ApiTestFuzzer::Fuzz();
    251   CHECK(info.GetIsolate() == v8::Isolate::GetCurrent());
    252   CHECK(info.This() == info.Holder());
    253   CHECK(info.Data()->Equals(v8::String::New("data")));
    254   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    255   CHECK(info.GetIsolate() == v8::Isolate::GetCurrent());
    256   CHECK(info.This() == info.Holder());
    257   CHECK(info.Data()->Equals(v8::String::New("data")));
    258   info.GetReturnValue().Set(17);
    259 }
    260 
    261 
    262 THREADED_TEST(DirectCall) {
    263   LocalContext context;
    264   v8::HandleScope scope(context->GetIsolate());
    265   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    266   obj->SetAccessor(v8_str("xxx"),
    267                    CheckAccessorArgsCorrect,
    268                    NULL,
    269                    v8::String::New("data"));
    270   v8::Handle<v8::Object> inst = obj->NewInstance();
    271   context->Global()->Set(v8::String::New("obj"), inst);
    272   Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
    273   for (int i = 0; i < 10; i++) {
    274     Local<Value> result = scr->Run();
    275     CHECK(!result.IsEmpty());
    276     CHECK_EQ(17, result->Int32Value());
    277   }
    278 }
    279 
    280 static void EmptyGetter(Local<String> name,
    281                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    282   CheckAccessorArgsCorrect(name, info);
    283   ApiTestFuzzer::Fuzz();
    284   CheckAccessorArgsCorrect(name, info);
    285   info.GetReturnValue().Set(v8::Handle<v8::Value>());
    286 }
    287 
    288 
    289 THREADED_TEST(EmptyResult) {
    290   LocalContext context;
    291   v8::HandleScope scope(context->GetIsolate());
    292   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    293   obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data"));
    294   v8::Handle<v8::Object> inst = obj->NewInstance();
    295   context->Global()->Set(v8::String::New("obj"), inst);
    296   Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
    297   for (int i = 0; i < 10; i++) {
    298     Local<Value> result = scr->Run();
    299     CHECK(result == v8::Undefined());
    300   }
    301 }
    302 
    303 
    304 THREADED_TEST(NoReuseRegress) {
    305   // Check that the IC generated for the one test doesn't get reused
    306   // for the other.
    307   v8::HandleScope scope(v8::Isolate::GetCurrent());
    308   {
    309     v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    310     obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data"));
    311     LocalContext context;
    312     v8::Handle<v8::Object> inst = obj->NewInstance();
    313     context->Global()->Set(v8::String::New("obj"), inst);
    314     Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
    315     for (int i = 0; i < 2; i++) {
    316       Local<Value> result = scr->Run();
    317       CHECK(result == v8::Undefined());
    318     }
    319   }
    320   {
    321     v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    322     obj->SetAccessor(v8_str("xxx"),
    323                      CheckAccessorArgsCorrect,
    324                      NULL,
    325                      v8::String::New("data"));
    326     LocalContext context;
    327     v8::Handle<v8::Object> inst = obj->NewInstance();
    328     context->Global()->Set(v8::String::New("obj"), inst);
    329     Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
    330     for (int i = 0; i < 10; i++) {
    331       Local<Value> result = scr->Run();
    332       CHECK(!result.IsEmpty());
    333       CHECK_EQ(17, result->Int32Value());
    334     }
    335   }
    336 }
    337 
    338 static void ThrowingGetAccessor(
    339     Local<String> name,
    340     const v8::PropertyCallbackInfo<v8::Value>& info) {
    341   ApiTestFuzzer::Fuzz();
    342   v8::ThrowException(v8_str("g"));
    343 }
    344 
    345 
    346 static void ThrowingSetAccessor(Local<String> name,
    347                                 Local<Value> value,
    348                                 const v8::PropertyCallbackInfo<void>& info) {
    349   v8::ThrowException(value);
    350 }
    351 
    352 
    353 THREADED_TEST(Regress1054726) {
    354   LocalContext env;
    355   v8::HandleScope scope(env->GetIsolate());
    356   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    357   obj->SetAccessor(v8_str("x"),
    358                    ThrowingGetAccessor,
    359                    ThrowingSetAccessor,
    360                    Local<Value>());
    361 
    362   env->Global()->Set(v8_str("obj"), obj->NewInstance());
    363 
    364   // Use the throwing property setter/getter in a loop to force
    365   // the accessor ICs to be initialized.
    366   v8::Handle<Value> result;
    367   result = Script::Compile(v8_str(
    368       "var result = '';"
    369       "for (var i = 0; i < 5; i++) {"
    370       "  try { obj.x; } catch (e) { result += e; }"
    371       "}; result"))->Run();
    372   CHECK_EQ(v8_str("ggggg"), result);
    373 
    374   result = Script::Compile(String::New(
    375       "var result = '';"
    376       "for (var i = 0; i < 5; i++) {"
    377       "  try { obj.x = i; } catch (e) { result += e; }"
    378       "}; result"))->Run();
    379   CHECK_EQ(v8_str("01234"), result);
    380 }
    381 
    382 
    383 static void AllocGetter(Local<String> name,
    384                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    385   ApiTestFuzzer::Fuzz();
    386   info.GetReturnValue().Set(v8::Array::New(1000));
    387 }
    388 
    389 
    390 THREADED_TEST(Gc) {
    391   LocalContext env;
    392   v8::HandleScope scope(env->GetIsolate());
    393   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    394   obj->SetAccessor(v8_str("xxx"), AllocGetter);
    395   env->Global()->Set(v8_str("obj"), obj->NewInstance());
    396   Script::Compile(String::New(
    397       "var last = [];"
    398       "for (var i = 0; i < 2048; i++) {"
    399       "  var result = obj.xxx;"
    400       "  result[0] = last;"
    401       "  last = result;"
    402       "}"))->Run();
    403 }
    404 
    405 
    406 static void StackCheck(Local<String> name,
    407                        const v8::PropertyCallbackInfo<v8::Value>& info) {
    408   i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
    409   for (int i = 0; !iter.done(); i++) {
    410     i::StackFrame* frame = iter.frame();
    411     CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
    412     i::Code* code = frame->LookupCode();
    413     CHECK(code->IsCode());
    414     i::Address pc = frame->pc();
    415     CHECK(code->contains(pc));
    416     iter.Advance();
    417   }
    418 }
    419 
    420 
    421 THREADED_TEST(StackIteration) {
    422   LocalContext env;
    423   v8::HandleScope scope(env->GetIsolate());
    424   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    425   i::StringStream::ClearMentionedObjectCache();
    426   obj->SetAccessor(v8_str("xxx"), StackCheck);
    427   env->Global()->Set(v8_str("obj"), obj->NewInstance());
    428   Script::Compile(String::New(
    429       "function foo() {"
    430       "  return obj.xxx;"
    431       "}"
    432       "for (var i = 0; i < 100; i++) {"
    433       "  foo();"
    434       "}"))->Run();
    435 }
    436 
    437 
    438 static void AllocateHandles(Local<String> name,
    439                             const v8::PropertyCallbackInfo<v8::Value>& info) {
    440   for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
    441     v8::Local<v8::Value>::New(name);
    442   }
    443   info.GetReturnValue().Set(v8::Integer::New(100));
    444 }
    445 
    446 
    447 THREADED_TEST(HandleScopeSegment) {
    448   // Check that we can return values past popping of handle scope
    449   // segments.
    450   LocalContext env;
    451   v8::HandleScope scope(env->GetIsolate());
    452   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    453   obj->SetAccessor(v8_str("xxx"), AllocateHandles);
    454   env->Global()->Set(v8_str("obj"), obj->NewInstance());
    455   v8::Handle<v8::Value> result = Script::Compile(String::New(
    456       "var result;"
    457       "for (var i = 0; i < 4; i++)"
    458       "  result = obj.xxx;"
    459       "result;"))->Run();
    460   CHECK_EQ(100, result->Int32Value());
    461 }
    462 
    463 
    464 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
    465   v8::Handle<v8::Array> array = v8::Array::New(1);
    466   array->Set(0, v8_str("regress"));
    467   info.GetReturnValue().Set(array);
    468 }
    469 
    470 
    471 void JSONStringifyGetter(Local<String> name,
    472                          const v8::PropertyCallbackInfo<v8::Value>& info) {
    473   info.GetReturnValue().Set(v8_str("crbug-161028"));
    474 }
    475 
    476 
    477 THREADED_TEST(JSONStringifyNamedInterceptorObject) {
    478   LocalContext env;
    479   v8::HandleScope scope(env->GetIsolate());
    480 
    481   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
    482   obj->SetNamedPropertyHandler(
    483       JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator);
    484   env->Global()->Set(v8_str("obj"), obj->NewInstance());
    485   v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
    486   CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
    487 }
    488