Home | History | Annotate | Download | only in src
      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 "v8.h"
     29 #include "accessors.h"
     30 
     31 #include "contexts.h"
     32 #include "deoptimizer.h"
     33 #include "execution.h"
     34 #include "factory.h"
     35 #include "frames-inl.h"
     36 #include "isolate.h"
     37 #include "list-inl.h"
     38 #include "property-details.h"
     39 
     40 namespace v8 {
     41 namespace internal {
     42 
     43 
     44 template <class C>
     45 static C* FindInPrototypeChain(Object* obj, bool* found_it) {
     46   ASSERT(!*found_it);
     47   Heap* heap = HEAP;
     48   while (!Is<C>(obj)) {
     49     if (obj == heap->null_value()) return NULL;
     50     obj = obj->GetPrototype();
     51   }
     52   *found_it = true;
     53   return C::cast(obj);
     54 }
     55 
     56 
     57 // Entry point that never should be called.
     58 MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
     59   UNREACHABLE();
     60   return NULL;
     61 }
     62 
     63 
     64 Object* Accessors::IllegalGetAccessor(Object* object, void*) {
     65   UNREACHABLE();
     66   return object;
     67 }
     68 
     69 
     70 MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
     71   // According to ECMA-262, section 8.6.2.2, page 28, setting
     72   // read-only properties must be silently ignored.
     73   return value;
     74 }
     75 
     76 
     77 //
     78 // Accessors::ArrayLength
     79 //
     80 
     81 
     82 MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
     83   // Traverse the prototype chain until we reach an array.
     84   bool found_it = false;
     85   JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
     86   if (!found_it) return Smi::FromInt(0);
     87   return holder->length();
     88 }
     89 
     90 
     91 // The helper function will 'flatten' Number objects.
     92 Object* Accessors::FlattenNumber(Object* value) {
     93   if (value->IsNumber() || !value->IsJSValue()) return value;
     94   JSValue* wrapper = JSValue::cast(value);
     95   ASSERT(Isolate::Current()->context()->global_context()->number_function()->
     96       has_initial_map());
     97   Map* number_map = Isolate::Current()->context()->global_context()->
     98       number_function()->initial_map();
     99   if (wrapper->map() == number_map) return wrapper->value();
    100   return value;
    101 }
    102 
    103 
    104 MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
    105   Isolate* isolate = object->GetIsolate();
    106 
    107   // This means one of the object's prototypes is a JSArray and the
    108   // object does not have a 'length' property.  Calling SetProperty
    109   // causes an infinite loop.
    110   if (!object->IsJSArray()) {
    111     return object->SetLocalPropertyIgnoreAttributes(
    112         isolate->heap()->length_symbol(), value, NONE);
    113   }
    114 
    115   value = FlattenNumber(value);
    116 
    117   // Need to call methods that may trigger GC.
    118   HandleScope scope(isolate);
    119 
    120   // Protect raw pointers.
    121   Handle<JSObject> object_handle(object, isolate);
    122   Handle<Object> value_handle(value, isolate);
    123 
    124   bool has_exception;
    125   Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
    126   if (has_exception) return Failure::Exception();
    127   Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
    128   if (has_exception) return Failure::Exception();
    129 
    130   if (uint32_v->Number() == number_v->Number()) {
    131     return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
    132   }
    133   return isolate->Throw(
    134       *isolate->factory()->NewRangeError("invalid_array_length",
    135                                          HandleVector<Object>(NULL, 0)));
    136 }
    137 
    138 
    139 const AccessorDescriptor Accessors::ArrayLength = {
    140   ArrayGetLength,
    141   ArraySetLength,
    142   0
    143 };
    144 
    145 
    146 //
    147 // Accessors::StringLength
    148 //
    149 
    150 
    151 MaybeObject* Accessors::StringGetLength(Object* object, void*) {
    152   Object* value = object;
    153   if (object->IsJSValue()) value = JSValue::cast(object)->value();
    154   if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
    155   // If object is not a string we return 0 to be compatible with WebKit.
    156   // Note: Firefox returns the length of ToString(object).
    157   return Smi::FromInt(0);
    158 }
    159 
    160 
    161 const AccessorDescriptor Accessors::StringLength = {
    162   StringGetLength,
    163   IllegalSetter,
    164   0
    165 };
    166 
    167 
    168 //
    169 // Accessors::ScriptSource
    170 //
    171 
    172 
    173 MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
    174   Object* script = JSValue::cast(object)->value();
    175   return Script::cast(script)->source();
    176 }
    177 
    178 
    179 const AccessorDescriptor Accessors::ScriptSource = {
    180   ScriptGetSource,
    181   IllegalSetter,
    182   0
    183 };
    184 
    185 
    186 //
    187 // Accessors::ScriptName
    188 //
    189 
    190 
    191 MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
    192   Object* script = JSValue::cast(object)->value();
    193   return Script::cast(script)->name();
    194 }
    195 
    196 
    197 const AccessorDescriptor Accessors::ScriptName = {
    198   ScriptGetName,
    199   IllegalSetter,
    200   0
    201 };
    202 
    203 
    204 //
    205 // Accessors::ScriptId
    206 //
    207 
    208 
    209 MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
    210   Object* script = JSValue::cast(object)->value();
    211   return Script::cast(script)->id();
    212 }
    213 
    214 
    215 const AccessorDescriptor Accessors::ScriptId = {
    216   ScriptGetId,
    217   IllegalSetter,
    218   0
    219 };
    220 
    221 
    222 //
    223 // Accessors::ScriptLineOffset
    224 //
    225 
    226 
    227 MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
    228   Object* script = JSValue::cast(object)->value();
    229   return Script::cast(script)->line_offset();
    230 }
    231 
    232 
    233 const AccessorDescriptor Accessors::ScriptLineOffset = {
    234   ScriptGetLineOffset,
    235   IllegalSetter,
    236   0
    237 };
    238 
    239 
    240 //
    241 // Accessors::ScriptColumnOffset
    242 //
    243 
    244 
    245 MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
    246   Object* script = JSValue::cast(object)->value();
    247   return Script::cast(script)->column_offset();
    248 }
    249 
    250 
    251 const AccessorDescriptor Accessors::ScriptColumnOffset = {
    252   ScriptGetColumnOffset,
    253   IllegalSetter,
    254   0
    255 };
    256 
    257 
    258 //
    259 // Accessors::ScriptData
    260 //
    261 
    262 
    263 MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
    264   Object* script = JSValue::cast(object)->value();
    265   return Script::cast(script)->data();
    266 }
    267 
    268 
    269 const AccessorDescriptor Accessors::ScriptData = {
    270   ScriptGetData,
    271   IllegalSetter,
    272   0
    273 };
    274 
    275 
    276 //
    277 // Accessors::ScriptType
    278 //
    279 
    280 
    281 MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
    282   Object* script = JSValue::cast(object)->value();
    283   return Script::cast(script)->type();
    284 }
    285 
    286 
    287 const AccessorDescriptor Accessors::ScriptType = {
    288   ScriptGetType,
    289   IllegalSetter,
    290   0
    291 };
    292 
    293 
    294 //
    295 // Accessors::ScriptCompilationType
    296 //
    297 
    298 
    299 MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
    300   Object* script = JSValue::cast(object)->value();
    301   return Script::cast(script)->compilation_type();
    302 }
    303 
    304 
    305 const AccessorDescriptor Accessors::ScriptCompilationType = {
    306   ScriptGetCompilationType,
    307   IllegalSetter,
    308   0
    309 };
    310 
    311 
    312 //
    313 // Accessors::ScriptGetLineEnds
    314 //
    315 
    316 
    317 MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
    318   JSValue* wrapper = JSValue::cast(object);
    319   Isolate* isolate = wrapper->GetIsolate();
    320   HandleScope scope(isolate);
    321   Handle<Script> script(Script::cast(wrapper->value()), isolate);
    322   InitScriptLineEnds(script);
    323   ASSERT(script->line_ends()->IsFixedArray());
    324   Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
    325   // We do not want anyone to modify this array from JS.
    326   ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
    327          line_ends->map() == isolate->heap()->fixed_cow_array_map());
    328   Handle<JSArray> js_array =
    329       isolate->factory()->NewJSArrayWithElements(line_ends);
    330   return *js_array;
    331 }
    332 
    333 
    334 const AccessorDescriptor Accessors::ScriptLineEnds = {
    335   ScriptGetLineEnds,
    336   IllegalSetter,
    337   0
    338 };
    339 
    340 
    341 //
    342 // Accessors::ScriptGetContextData
    343 //
    344 
    345 
    346 MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
    347   Object* script = JSValue::cast(object)->value();
    348   return Script::cast(script)->context_data();
    349 }
    350 
    351 
    352 const AccessorDescriptor Accessors::ScriptContextData = {
    353   ScriptGetContextData,
    354   IllegalSetter,
    355   0
    356 };
    357 
    358 
    359 //
    360 // Accessors::ScriptGetEvalFromScript
    361 //
    362 
    363 
    364 MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
    365   Object* script = JSValue::cast(object)->value();
    366   if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
    367     Handle<SharedFunctionInfo> eval_from_shared(
    368         SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
    369 
    370     if (eval_from_shared->script()->IsScript()) {
    371       Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
    372       return *GetScriptWrapper(eval_from_script);
    373     }
    374   }
    375   return HEAP->undefined_value();
    376 }
    377 
    378 
    379 const AccessorDescriptor Accessors::ScriptEvalFromScript = {
    380   ScriptGetEvalFromScript,
    381   IllegalSetter,
    382   0
    383 };
    384 
    385 
    386 //
    387 // Accessors::ScriptGetEvalFromScriptPosition
    388 //
    389 
    390 
    391 MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
    392   HandleScope scope;
    393   Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
    394 
    395   // If this is not a script compiled through eval there is no eval position.
    396   int compilation_type = Smi::cast(script->compilation_type())->value();
    397   if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
    398     return HEAP->undefined_value();
    399   }
    400 
    401   // Get the function from where eval was called and find the source position
    402   // from the instruction offset.
    403   Handle<Code> code(SharedFunctionInfo::cast(
    404       script->eval_from_shared())->code());
    405   return Smi::FromInt(code->SourcePosition(code->instruction_start() +
    406                       script->eval_from_instructions_offset()->value()));
    407 }
    408 
    409 
    410 const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
    411   ScriptGetEvalFromScriptPosition,
    412   IllegalSetter,
    413   0
    414 };
    415 
    416 
    417 //
    418 // Accessors::ScriptGetEvalFromFunctionName
    419 //
    420 
    421 
    422 MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
    423   Object* script = JSValue::cast(object)->value();
    424   Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
    425       Script::cast(script)->eval_from_shared()));
    426 
    427 
    428   // Find the name of the function calling eval.
    429   if (!shared->name()->IsUndefined()) {
    430     return shared->name();
    431   } else {
    432     return shared->inferred_name();
    433   }
    434 }
    435 
    436 
    437 const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
    438   ScriptGetEvalFromFunctionName,
    439   IllegalSetter,
    440   0
    441 };
    442 
    443 
    444 //
    445 // Accessors::FunctionPrototype
    446 //
    447 
    448 
    449 MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
    450   Heap* heap = Isolate::Current()->heap();
    451   bool found_it = false;
    452   JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
    453   if (!found_it) return heap->undefined_value();
    454   while (!function->should_have_prototype()) {
    455     found_it = false;
    456     function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
    457                                                 &found_it);
    458     // There has to be one because we hit the getter.
    459     ASSERT(found_it);
    460   }
    461 
    462   if (!function->has_prototype()) {
    463     Object* prototype;
    464     { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
    465       if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
    466     }
    467     Object* result;
    468     { MaybeObject* maybe_result = function->SetPrototype(prototype);
    469       if (!maybe_result->ToObject(&result)) return maybe_result;
    470     }
    471   }
    472   return function->prototype();
    473 }
    474 
    475 
    476 MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
    477                                              Object* value,
    478                                              void*) {
    479   Heap* heap = object->GetHeap();
    480   bool found_it = false;
    481   JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
    482   if (!found_it) return heap->undefined_value();
    483   if (!function->should_have_prototype()) {
    484     // Since we hit this accessor, object will have no prototype property.
    485     return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
    486                                                     value,
    487                                                     NONE);
    488   }
    489 
    490   Object* prototype;
    491   { MaybeObject* maybe_prototype = function->SetPrototype(value);
    492     if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
    493   }
    494   ASSERT(function->prototype() == value);
    495   return function;
    496 }
    497 
    498 
    499 const AccessorDescriptor Accessors::FunctionPrototype = {
    500   FunctionGetPrototype,
    501   FunctionSetPrototype,
    502   0
    503 };
    504 
    505 
    506 //
    507 // Accessors::FunctionLength
    508 //
    509 
    510 
    511 MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
    512   bool found_it = false;
    513   JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
    514   if (!found_it) return Smi::FromInt(0);
    515   // Check if already compiled.
    516   if (!function->shared()->is_compiled()) {
    517     // If the function isn't compiled yet, the length is not computed
    518     // correctly yet. Compile it now and return the right length.
    519     HandleScope scope;
    520     Handle<JSFunction> handle(function);
    521     if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
    522       return Failure::Exception();
    523     }
    524     return Smi::FromInt(handle->shared()->length());
    525   } else {
    526     return Smi::FromInt(function->shared()->length());
    527   }
    528 }
    529 
    530 
    531 const AccessorDescriptor Accessors::FunctionLength = {
    532   FunctionGetLength,
    533   ReadOnlySetAccessor,
    534   0
    535 };
    536 
    537 
    538 //
    539 // Accessors::FunctionName
    540 //
    541 
    542 
    543 MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
    544   bool found_it = false;
    545   JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
    546   if (!found_it) return HEAP->undefined_value();
    547   return holder->shared()->name();
    548 }
    549 
    550 
    551 const AccessorDescriptor Accessors::FunctionName = {
    552   FunctionGetName,
    553   ReadOnlySetAccessor,
    554   0
    555 };
    556 
    557 
    558 //
    559 // Accessors::FunctionArguments
    560 //
    561 
    562 
    563 static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
    564     JavaScriptFrame* frame,
    565     Handle<JSFunction> inlined_function,
    566     int inlined_frame_index) {
    567   Factory* factory = Isolate::Current()->factory();
    568   Vector<SlotRef> args_slots =
    569       SlotRef::ComputeSlotMappingForArguments(
    570           frame,
    571           inlined_frame_index,
    572           inlined_function->shared()->formal_parameter_count());
    573   int args_count = args_slots.length();
    574   Handle<JSObject> arguments =
    575       factory->NewArgumentsObject(inlined_function, args_count);
    576   Handle<FixedArray> array = factory->NewFixedArray(args_count);
    577   for (int i = 0; i < args_count; ++i) {
    578     Handle<Object> value = args_slots[i].GetValue();
    579     array->set(i, *value);
    580   }
    581   arguments->set_elements(*array);
    582   args_slots.Dispose();
    583 
    584   // Return the freshly allocated arguments object.
    585   return *arguments;
    586 }
    587 
    588 
    589 MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
    590   Isolate* isolate = Isolate::Current();
    591   HandleScope scope(isolate);
    592   bool found_it = false;
    593   JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
    594   if (!found_it) return isolate->heap()->undefined_value();
    595   Handle<JSFunction> function(holder, isolate);
    596 
    597   if (function->shared()->native()) return isolate->heap()->null_value();
    598   // Find the top invocation of the function by traversing frames.
    599   List<JSFunction*> functions(2);
    600   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
    601     JavaScriptFrame* frame = it.frame();
    602     frame->GetFunctions(&functions);
    603     for (int i = functions.length() - 1; i >= 0; i--) {
    604       // Skip all frames that aren't invocations of the given function.
    605       if (functions[i] != *function) continue;
    606 
    607       if (i > 0) {
    608         // The function in question was inlined.  Inlined functions have the
    609         // correct number of arguments and no allocated arguments object, so
    610         // we can construct a fresh one by interpreting the function's
    611         // deoptimization input data.
    612         return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
    613       }
    614 
    615       if (!frame->is_optimized()) {
    616         // If there is an arguments variable in the stack, we return that.
    617         Handle<ScopeInfo> scope_info(function->shared()->scope_info());
    618         int index = scope_info->StackSlotIndex(
    619             isolate->heap()->arguments_symbol());
    620         if (index >= 0) {
    621           Handle<Object> arguments(frame->GetExpression(index), isolate);
    622           if (!arguments->IsArgumentsMarker()) return *arguments;
    623         }
    624       }
    625 
    626       // If there is no arguments variable in the stack or we have an
    627       // optimized frame, we find the frame that holds the actual arguments
    628       // passed to the function.
    629       it.AdvanceToArgumentsFrame();
    630       frame = it.frame();
    631 
    632       // Get the number of arguments and construct an arguments object
    633       // mirror for the right frame.
    634       const int length = frame->ComputeParametersCount();
    635       Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
    636           function, length);
    637       Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
    638 
    639       // Copy the parameters to the arguments object.
    640       ASSERT(array->length() == length);
    641       for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
    642       arguments->set_elements(*array);
    643 
    644       // Return the freshly allocated arguments object.
    645       return *arguments;
    646     }
    647     functions.Rewind(0);
    648   }
    649 
    650   // No frame corresponding to the given function found. Return null.
    651   return isolate->heap()->null_value();
    652 }
    653 
    654 
    655 const AccessorDescriptor Accessors::FunctionArguments = {
    656   FunctionGetArguments,
    657   ReadOnlySetAccessor,
    658   0
    659 };
    660 
    661 
    662 //
    663 // Accessors::FunctionCaller
    664 //
    665 
    666 
    667 static MaybeObject* CheckNonStrictCallerOrThrow(
    668     Isolate* isolate,
    669     JSFunction* caller) {
    670   DisableAssertNoAllocation enable_allocation;
    671   if (!caller->shared()->is_classic_mode()) {
    672     return isolate->Throw(
    673         *isolate->factory()->NewTypeError("strict_caller",
    674                                           HandleVector<Object>(NULL, 0)));
    675   }
    676   return caller;
    677 }
    678 
    679 
    680 class FrameFunctionIterator {
    681  public:
    682   FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
    683       : frame_iterator_(isolate),
    684         functions_(2),
    685         index_(0) {
    686     GetFunctions();
    687   }
    688   JSFunction* next() {
    689     if (functions_.length() == 0) return NULL;
    690     JSFunction* next_function = functions_[index_];
    691     index_--;
    692     if (index_ < 0) {
    693       GetFunctions();
    694     }
    695     return next_function;
    696   }
    697 
    698   // Iterate through functions until the first occurence of 'function'.
    699   // Returns true if 'function' is found, and false if the iterator ends
    700   // without finding it.
    701   bool Find(JSFunction* function) {
    702     JSFunction* next_function;
    703     do {
    704       next_function = next();
    705       if (next_function == function) return true;
    706     } while (next_function != NULL);
    707     return false;
    708   }
    709 
    710  private:
    711   void GetFunctions() {
    712     functions_.Rewind(0);
    713     if (frame_iterator_.done()) return;
    714     JavaScriptFrame* frame = frame_iterator_.frame();
    715     frame->GetFunctions(&functions_);
    716     ASSERT(functions_.length() > 0);
    717     frame_iterator_.Advance();
    718     index_ = functions_.length() - 1;
    719   }
    720   JavaScriptFrameIterator frame_iterator_;
    721   List<JSFunction*> functions_;
    722   int index_;
    723 };
    724 
    725 
    726 MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
    727   Isolate* isolate = Isolate::Current();
    728   HandleScope scope(isolate);
    729   AssertNoAllocation no_alloc;
    730   bool found_it = false;
    731   JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
    732   if (!found_it) return isolate->heap()->undefined_value();
    733   if (holder->shared()->native()) return isolate->heap()->null_value();
    734   Handle<JSFunction> function(holder, isolate);
    735 
    736   FrameFunctionIterator it(isolate, no_alloc);
    737 
    738   // Find the function from the frames.
    739   if (!it.Find(*function)) {
    740     // No frame corresponding to the given function found. Return null.
    741     return isolate->heap()->null_value();
    742   }
    743 
    744   // Find previously called non-toplevel function.
    745   JSFunction* caller;
    746   do {
    747     caller = it.next();
    748     if (caller == NULL) return isolate->heap()->null_value();
    749   } while (caller->shared()->is_toplevel());
    750 
    751   // If caller is a built-in function and caller's caller is also built-in,
    752   // use that instead.
    753   JSFunction* potential_caller = caller;
    754   while (potential_caller != NULL && potential_caller->IsBuiltin()) {
    755     caller = potential_caller;
    756     potential_caller = it.next();
    757   }
    758   // If caller is bound, return null. This is compatible with JSC, and
    759   // allows us to make bound functions use the strict function map
    760   // and its associated throwing caller and arguments.
    761   if (caller->shared()->bound()) {
    762     return isolate->heap()->null_value();
    763   }
    764   return CheckNonStrictCallerOrThrow(isolate, caller);
    765 }
    766 
    767 
    768 const AccessorDescriptor Accessors::FunctionCaller = {
    769   FunctionGetCaller,
    770   ReadOnlySetAccessor,
    771   0
    772 };
    773 
    774 
    775 //
    776 // Accessors::ObjectPrototype
    777 //
    778 
    779 
    780 MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
    781   Object* current = receiver->GetPrototype();
    782   while (current->IsJSObject() &&
    783          JSObject::cast(current)->map()->is_hidden_prototype()) {
    784     current = current->GetPrototype();
    785   }
    786   return current;
    787 }
    788 
    789 
    790 MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
    791                                            Object* value,
    792                                            void*) {
    793   const bool skip_hidden_prototypes = true;
    794   // To be consistent with other Set functions, return the value.
    795   return receiver->SetPrototype(value, skip_hidden_prototypes);
    796 }
    797 
    798 
    799 const AccessorDescriptor Accessors::ObjectPrototype = {
    800   ObjectGetPrototype,
    801   ObjectSetPrototype,
    802   0
    803 };
    804 
    805 } }  // namespace v8::internal
    806