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