From 2f2f90610e2befb2e2a7e1867054c86b23cc000c Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Thu, 25 Aug 2011 13:38:58 +0000 Subject: [PATCH] Changed computation of func.caller to skip some built-in functions. Now skips built-in functions called from other built-in functions, so only the initally called built-in function is exposed. Review URL: http://codereview.chromium.org/7740021 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9018 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/accessors.cc | 97 ++++++++++++++++++++++++++++------------- test/mjsunit/function-caller.js | 7 +++ 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/accessors.cc b/src/accessors.cc index 806c679..e7d6aa0 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 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 function(holder, isolate); - List 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); } diff --git a/test/mjsunit/function-caller.js b/test/mjsunit/function-caller.js index ddc7b5d..bc01750 100644 --- a/test/mjsunit/function-caller.js +++ b/test/mjsunit/function-caller.js @@ -46,3 +46,10 @@ f(null); // Check called from eval. eval('f(null)'); +// Check called from builtin functions. Only show the initially called +// (publicly exposed) builtin function, not it's internal helper functions. +[Array.prototype.sort, Array.prototype.sort].sort(f); + +"abel".replace(/b/g, function h() { + assertEquals(String.prototype.replace, h.caller); +}); -- 2.7.4