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); |
} |