Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1b54636

Browse files
author
lrn@chromium.org
committedAug 25, 2011
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: https://v8.googlecode.com/svn/branches/bleeding_edge@9018 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
1 parent c4a25e9 commit 1b54636

File tree

2 files changed

+74
-30
lines changed

2 files changed

+74
-30
lines changed
 

‎src/accessors.cc

+67-30
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,51 @@ static MaybeObject* CheckNonStrictCallerOrThrow(
680680
}
681681

682682

683+
class FrameFunctionIterator {
684+
public:
685+
FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
686+
: frame_iterator_(isolate),
687+
functions_(2),
688+
index_(0) {
689+
GetFunctions();
690+
}
691+
JSFunction* next() {
692+
if (functions_.length() == 0) return NULL;
693+
JSFunction* next_function = functions_[index_];
694+
index_--;
695+
if (index_ < 0) {
696+
GetFunctions();
697+
}
698+
return next_function;
699+
}
700+
701+
// Iterate through functions until the first occurence of 'function'.
702+
// Returns true if 'function' is found, and false if the iterator ends
703+
// without finding it.
704+
bool Find(JSFunction* function) {
705+
JSFunction* next_function;
706+
do {
707+
next_function = next();
708+
if (next_function == function) return true;
709+
} while (next_function != NULL);
710+
return false;
711+
}
712+
private:
713+
void GetFunctions() {
714+
functions_.Rewind(0);
715+
if (frame_iterator_.done()) return;
716+
JavaScriptFrame* frame = frame_iterator_.frame();
717+
frame->GetFunctions(&functions_);
718+
ASSERT(functions_.length() > 0);
719+
frame_iterator_.Advance();
720+
index_ = functions_.length() - 1;
721+
}
722+
JavaScriptFrameIterator frame_iterator_;
723+
List<JSFunction*> functions_;
724+
int index_;
725+
};
726+
727+
683728
MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
684729
Isolate* isolate = Isolate::Current();
685730
HandleScope scope(isolate);
@@ -689,38 +734,30 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
689734
if (!found_it) return isolate->heap()->undefined_value();
690735
Handle<JSFunction> function(holder, isolate);
691736

692-
List<JSFunction*> functions(2);
693-
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
694-
JavaScriptFrame* frame = it.frame();
695-
frame->GetFunctions(&functions);
696-
for (int i = functions.length() - 1; i >= 0; i--) {
697-
if (functions[i] == *function) {
698-
// Once we have found the frame, we need to go to the caller
699-
// frame. This may require skipping through a number of top-level
700-
// frames, e.g. frames for scripts not functions.
701-
if (i > 0) {
702-
ASSERT(!functions[i - 1]->shared()->is_toplevel());
703-
return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
704-
} else {
705-
for (it.Advance(); !it.done(); it.Advance()) {
706-
frame = it.frame();
707-
functions.Rewind(0);
708-
frame->GetFunctions(&functions);
709-
if (!functions.last()->shared()->is_toplevel()) {
710-
return CheckNonStrictCallerOrThrow(isolate, functions.last());
711-
}
712-
ASSERT(functions.length() == 1);
713-
}
714-
if (it.done()) return isolate->heap()->null_value();
715-
break;
716-
}
717-
}
718-
}
719-
functions.Rewind(0);
737+
FrameFunctionIterator it(isolate, no_alloc);
738+
739+
// Find the function from the frames.
740+
if (!it.Find(*function)) {
741+
// No frame corresponding to the given function found. Return null.
742+
return isolate->heap()->null_value();
720743
}
721744

722-
// No frame corresponding to the given function found. Return null.
723-
return isolate->heap()->null_value();
745+
// Find previously called non-toplevel function.
746+
JSFunction* caller;
747+
do {
748+
caller = it.next();
749+
if (caller == NULL) return isolate->heap()->null_value();
750+
} while (caller->shared()->is_toplevel());
751+
752+
// If caller is a built-in function and caller's caller is also built-in,
753+
// use that instead.
754+
JSFunction* potential_caller = caller;
755+
while (potential_caller != NULL && potential_caller->IsBuiltin()) {
756+
caller = potential_caller;
757+
potential_caller = it.next();
758+
}
759+
760+
return CheckNonStrictCallerOrThrow(isolate, caller);
724761
}
725762

726763

‎test/mjsunit/function-caller.js

+7
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,10 @@ f(null);
4646
// Check called from eval.
4747
eval('f(null)');
4848

49+
// Check called from builtin functions. Only show the initially called
50+
// (publicly exposed) builtin function, not it's internal helper functions.
51+
[Array.prototype.sort, Array.prototype.sort].sort(f);
52+
53+
"abel".replace(/b/g, function h() {
54+
assertEquals(String.prototype.replace, h.caller);
55+
});

0 commit comments

Comments
 (0)
Please sign in to comment.