• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
FindInPrototypeChain(Object * obj,bool * found_it)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.
IllegalSetter(JSObject *,Object *,void *)58 MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
59   UNREACHABLE();
60   return NULL;
61 }
62 
63 
IllegalGetAccessor(Object * object,void *)64 Object* Accessors::IllegalGetAccessor(Object* object, void*) {
65   UNREACHABLE();
66   return object;
67 }
68 
69 
ReadOnlySetAccessor(JSObject *,Object * value,void *)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 
ArrayGetLength(Object * object,void *)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.
FlattenNumber(Object * value)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 
ArraySetLength(JSObject * object,Object * value,void *)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 
StringGetLength(Object * object,void *)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 
ScriptGetSource(Object * object,void *)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 
ScriptGetName(Object * object,void *)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 
ScriptGetId(Object * object,void *)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 
ScriptGetLineOffset(Object * object,void *)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 
ScriptGetColumnOffset(Object * object,void *)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 
ScriptGetData(Object * object,void *)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 
ScriptGetType(Object * object,void *)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 
ScriptGetCompilationType(Object * object,void *)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 
ScriptGetLineEnds(Object * object,void *)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 
ScriptGetContextData(Object * object,void *)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 
ScriptGetEvalFromScript(Object * object,void *)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 
ScriptGetEvalFromScriptPosition(Object * object,void *)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 
ScriptGetEvalFromFunctionName(Object * object,void *)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 
FunctionGetPrototype(Object * object,void *)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 
FunctionSetPrototype(JSObject * object,Object * value,void *)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 
FunctionGetLength(Object * object,void *)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 
FunctionGetName(Object * object,void *)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 
ConstructArgumentsObjectForInlinedFunction(JavaScriptFrame * frame,Handle<JSFunction> inlined_function,int inlined_frame_index)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 
FunctionGetArguments(Object * object,void *)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 
CheckNonStrictCallerOrThrow(Isolate * isolate,JSFunction * caller)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:
FrameFunctionIterator(Isolate * isolate,const AssertNoAllocation & promise)682   FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
683       : frame_iterator_(isolate),
684         functions_(2),
685         index_(0) {
686     GetFunctions();
687   }
next()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.
Find(JSFunction * function)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:
GetFunctions()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 
FunctionGetCaller(Object * object,void *)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 
ObjectGetPrototype(Object * receiver,void *)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 
ObjectSetPrototype(JSObject * receiver,Object * value,void *)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