• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
FindInPrototypeChain(Object * obj,bool * found_it)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.
IllegalSetter(JSObject *,Object *,void *)56 MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
57   UNREACHABLE();
58   return NULL;
59 }
60 
61 
IllegalGetAccessor(Object * object,void *)62 Object* Accessors::IllegalGetAccessor(Object* object, void*) {
63   UNREACHABLE();
64   return object;
65 }
66 
67 
ReadOnlySetAccessor(JSObject *,Object * value,void *)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 
ArrayGetLength(Object * object,void *)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.
FlattenNumber(Object * value)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 
ArraySetLength(JSObject * object,Object * value,void *)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 
StringGetLength(Object * object,void *)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 
ScriptGetSource(Object * object,void *)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 
ScriptGetName(Object * object,void *)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 
ScriptGetId(Object * object,void *)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 
ScriptGetLineOffset(Object * object,void *)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 
ScriptGetColumnOffset(Object * object,void *)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 
ScriptGetData(Object * object,void *)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 
ScriptGetType(Object * object,void *)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 
ScriptGetCompilationType(Object * object,void *)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 
ScriptGetLineEnds(Object * object,void *)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 
ScriptGetContextData(Object * object,void *)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 
ScriptGetEvalFromScript(Object * object,void *)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 
ScriptGetEvalFromScriptPosition(Object * object,void *)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 
ScriptGetEvalFromFunctionName(Object * object,void *)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 
FunctionGetPrototype(Object * object,void *)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 
FunctionSetPrototype(JSObject * object,Object * value,void *)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 
FunctionGetLength(Object * object,void *)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 
FunctionGetName(Object * object,void *)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 
ConstructArgumentsObjectForInlinedFunction(JavaScriptFrame * frame,Handle<JSFunction> inlined_function,int inlined_frame_index)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 
FunctionGetArguments(Object * object,void *)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 
CheckNonStrictCallerOrThrow(Isolate * isolate,JSFunction * caller)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 
FunctionGetCaller(Object * object,void *)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 
ObjectGetPrototype(Object * receiver,void *)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 
ObjectSetPrototype(JSObject * receiver,Object * value,void *)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