| Index: src/accessors.cc | 
| diff --git a/src/accessors.cc b/src/accessors.cc | 
| index 806c679f4bc82ef016777fb8c329ca2637489a49..e7d6aa0e8b66483ba510c4720945d0d97c82457a 100644 | 
| --- a/src/accessors.cc | 
| +++ b/src/accessors.cc | 
| @@ -680,6 +680,51 @@ static MaybeObject* CheckNonStrictCallerOrThrow( | 
| } | 
|  | 
|  | 
| +class FrameFunctionIterator { | 
| + public: | 
| +  FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise) | 
| +      : frame_iterator_(isolate), | 
| +        functions_(2), | 
| +        index_(0) { | 
| +    GetFunctions(); | 
| +  } | 
| +  JSFunction* next() { | 
| +    if (functions_.length() == 0) return NULL; | 
| +    JSFunction* next_function = functions_[index_]; | 
| +    index_--; | 
| +    if (index_ < 0) { | 
| +      GetFunctions(); | 
| +    } | 
| +    return next_function; | 
| +  } | 
| + | 
| +  // Iterate through functions until the first occurence of 'function'. | 
| +  // Returns true if 'function' is found, and false if the iterator ends | 
| +  // without finding it. | 
| +  bool Find(JSFunction* function) { | 
| +    JSFunction* next_function; | 
| +    do { | 
| +      next_function = next(); | 
| +      if (next_function == function) return true; | 
| +    } while (next_function != NULL); | 
| +    return false; | 
| +  } | 
| + private: | 
| +  void GetFunctions() { | 
| +    functions_.Rewind(0); | 
| +    if (frame_iterator_.done()) return; | 
| +    JavaScriptFrame* frame = frame_iterator_.frame(); | 
| +    frame->GetFunctions(&functions_); | 
| +    ASSERT(functions_.length() > 0); | 
| +    frame_iterator_.Advance(); | 
| +    index_ = functions_.length() - 1; | 
| +  } | 
| +  JavaScriptFrameIterator frame_iterator_; | 
| +  List<JSFunction*> functions_; | 
| +  int index_; | 
| +}; | 
| + | 
| + | 
| MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { | 
| Isolate* isolate = Isolate::Current(); | 
| HandleScope scope(isolate); | 
| @@ -689,38 +734,30 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { | 
| if (!found_it) return isolate->heap()->undefined_value(); | 
| Handle<JSFunction> function(holder, isolate); | 
|  | 
| -  List<JSFunction*> functions(2); | 
| -  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { | 
| -    JavaScriptFrame* frame = it.frame(); | 
| -    frame->GetFunctions(&functions); | 
| -    for (int i = functions.length() - 1; i >= 0; i--) { | 
| -      if (functions[i] == *function) { | 
| -        // Once we have found the frame, we need to go to the caller | 
| -        // frame. This may require skipping through a number of top-level | 
| -        // frames, e.g. frames for scripts not functions. | 
| -        if (i > 0) { | 
| -          ASSERT(!functions[i - 1]->shared()->is_toplevel()); | 
| -          return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]); | 
| -        } else { | 
| -          for (it.Advance(); !it.done(); it.Advance()) { | 
| -            frame = it.frame(); | 
| -            functions.Rewind(0); | 
| -            frame->GetFunctions(&functions); | 
| -            if (!functions.last()->shared()->is_toplevel()) { | 
| -              return CheckNonStrictCallerOrThrow(isolate, functions.last()); | 
| -            } | 
| -            ASSERT(functions.length() == 1); | 
| -          } | 
| -          if (it.done()) return isolate->heap()->null_value(); | 
| -          break; | 
| -        } | 
| -      } | 
| -    } | 
| -    functions.Rewind(0); | 
| +  FrameFunctionIterator it(isolate, no_alloc); | 
| + | 
| +  // Find the function from the frames. | 
| +  if (!it.Find(*function)) { | 
| +    // No frame corresponding to the given function found. Return null. | 
| +    return isolate->heap()->null_value(); | 
| } | 
|  | 
| -  // No frame corresponding to the given function found. Return null. | 
| -  return isolate->heap()->null_value(); | 
| +  // Find previously called non-toplevel function. | 
| +  JSFunction* caller; | 
| +  do { | 
| +    caller = it.next(); | 
| +    if (caller == NULL) return isolate->heap()->null_value(); | 
| +  } while (caller->shared()->is_toplevel()); | 
| + | 
| +  // If caller is a built-in function and caller's caller is also built-in, | 
| +  // use that instead. | 
| +  JSFunction* potential_caller = caller; | 
| +  while (potential_caller != NULL && potential_caller->IsBuiltin()) { | 
| +    caller = potential_caller; | 
| +    potential_caller = it.next(); | 
| +  } | 
| + | 
| +  return CheckNonStrictCallerOrThrow(isolate, caller); | 
| } | 
|  | 
|  | 
|  |