Chromium Code Reviews| Index: src/accessors.cc |
| diff --git a/src/accessors.cc b/src/accessors.cc |
| index 806c679f4bc82ef016777fb8c329ca2637489a49..6c09264625537e4b79bd67197b8186d193bbb7a6 100644 |
| --- a/src/accessors.cc |
| +++ b/src/accessors.cc |
| @@ -680,6 +680,48 @@ 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; |
| + } |
| + |
| + 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 +731,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. |
| + for (JSFunction* potential_caller = caller; |
| + potential_caller != NULL && potential_caller->IsBuiltin(); |
|
William Hesse
2011/08/25 13:29:48
I think this is clearer as a while loop, or anythi
Lasse Reichstein
2011/08/25 13:34:12
Done.
|
| + potential_caller = it.next()) { |
| + caller = potential_caller; |
| + } |
| + |
| + return CheckNonStrictCallerOrThrow(isolate, caller); |
| } |