Move more parts of stack trace formatting to runtime.

R=ishell@chromium.org

Review URL: https://codereview.chromium.org/1122973002

Cr-Commit-Position: refs/heads/master@{#28223}
This commit is contained in:
yangguo 2015-05-05 06:55:28 -07:00 committed by Commit bot
parent 3283195d04
commit 7546302b67
8 changed files with 107 additions and 32 deletions

View File

@ -197,6 +197,67 @@ Handle<Object> CallSite::GetScriptNameOrSourceUrl(Isolate* isolate) {
}
bool CheckMethodName(Handle<JSObject> obj, Handle<Name> name,
Handle<JSFunction> fun,
LookupIterator::Configuration config) {
LookupIterator iter(obj, name, config);
if (iter.state() == LookupIterator::DATA) {
return iter.GetDataValue().is_identical_to(fun);
} else if (iter.state() == LookupIterator::ACCESSOR) {
Handle<Object> accessors = iter.GetAccessors();
if (accessors->IsAccessorPair()) {
Handle<AccessorPair> pair = Handle<AccessorPair>::cast(accessors);
return pair->getter() == *fun || pair->setter() == *fun;
}
}
return false;
}
Handle<Object> CallSite::GetMethodName(Isolate* isolate) {
MaybeHandle<JSReceiver> maybe = Object::ToObject(isolate, receiver_);
Handle<JSReceiver> receiver;
if (!maybe.ToHandle(&receiver) || !receiver->IsJSObject()) {
return isolate->factory()->null_value();
}
Handle<JSObject> obj = Handle<JSObject>::cast(receiver);
Handle<Object> function_name(fun_->shared()->name(), isolate);
if (function_name->IsName()) {
Handle<Name> name = Handle<Name>::cast(function_name);
if (CheckMethodName(obj, name, fun_,
LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR))
return name;
}
HandleScope outer_scope(isolate);
Handle<Object> result;
for (PrototypeIterator iter(isolate, obj,
PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(); iter.Advance()) {
Handle<Object> current = PrototypeIterator::GetCurrent(iter);
if (!current->IsJSObject()) break;
Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
if (current_obj->IsAccessCheckNeeded()) break;
Handle<FixedArray> keys = JSObject::GetEnumPropertyKeys(current_obj, false);
for (int i = 0; i < keys->length(); i++) {
HandleScope inner_scope(isolate);
if (!keys->get(i)->IsName()) continue;
Handle<Name> name_key(Name::cast(keys->get(i)), isolate);
if (!CheckMethodName(current_obj, name_key, fun_,
LookupIterator::OWN_SKIP_INTERCEPTOR))
continue;
// Return null in case of duplicates to avoid confusion.
if (!result.is_null()) return isolate->factory()->null_value();
result = inner_scope.CloseAndEscape(name_key);
}
}
if (!result.is_null()) return outer_scope.CloseAndEscape(result);
return isolate->factory()->null_value();
}
int CallSite::GetLineNumber(Isolate* isolate) {
if (pos_ >= 0) {
Handle<Object> script_obj(fun_->shared()->script(), isolate);
@ -242,6 +303,15 @@ bool CallSite::IsEval(Isolate* isolate) {
}
bool CallSite::IsConstructor(Isolate* isolate) {
if (!receiver_->IsJSObject()) return false;
Handle<Object> constructor =
JSObject::GetDataProperty(Handle<JSObject>::cast(receiver_),
isolate->factory()->constructor_string());
return constructor.is_identical_to(fun_);
}
MaybeHandle<String> MessageTemplate::FormatMessage(int template_index,
Handle<String> arg0,
Handle<String> arg1,

View File

@ -96,6 +96,7 @@ class CallSite {
Handle<Object> GetFileName(Isolate* isolate);
Handle<Object> GetFunctionName(Isolate* isolate);
Handle<Object> GetScriptNameOrSourceUrl(Isolate* isolate);
Handle<Object> GetMethodName(Isolate* isolate);
// Return 1-based line number, including line offset.
int GetLineNumber(Isolate* isolate);
// Return 1-based column number, including column offset if first line.
@ -103,6 +104,7 @@ class CallSite {
bool IsNative(Isolate* isolate);
bool IsToplevel(Isolate* isolate);
bool IsEval(Isolate* isolate);
bool IsConstructor(Isolate* isolate);
private:
Handle<Object> receiver_;

View File

@ -778,31 +778,8 @@ function CallSiteGetMethodName() {
// this function.
var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
var fun = GET_PRIVATE(this, CallSiteFunctionKey);
var ownName = fun.name;
if (ownName && receiver &&
(%_CallFunction(receiver, ownName, $objectLookupGetter) === fun ||
%_CallFunction(receiver, ownName, $objectLookupSetter) === fun ||
(IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) {
// To handle DontEnum properties we guess that the method has
// the same name as the function.
return ownName;
}
var name = null;
for (var prop in receiver) {
if (%_CallFunction(receiver, prop, $objectLookupGetter) === fun ||
%_CallFunction(receiver, prop, $objectLookupSetter) === fun ||
(IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) {
// If we find more than one match bail out to avoid confusion.
if (name) {
return null;
}
name = prop;
}
}
if (name) {
return name;
}
return null;
var pos = GET_PRIVATE(this, CallSitePositionKey);
return %CallSiteGetMethodNameRT(receiver, fun, pos);
}
function CallSiteGetFileName() {
@ -835,10 +812,9 @@ function CallSiteIsNative() {
function CallSiteIsConstructor() {
var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
var constructor = (receiver != null && IS_OBJECT(receiver))
? %GetDataProperty(receiver, "constructor") : null;
if (!constructor) return false;
return GET_PRIVATE(this, CallSiteFunctionKey) === constructor;
var fun = GET_PRIVATE(this, CallSiteFunctionKey);
var pos = GET_PRIVATE(this, CallSitePositionKey);
return %CallSiteIsConstructorRT(receiver, fun, pos);
}
function CallSiteToString() {

View File

@ -6240,8 +6240,8 @@ static Handle<FixedArray> ReduceFixedArrayTo(
}
static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result) {
Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result) {
Isolate* isolate = object->GetIsolate();
if (object->HasFastProperties()) {
int own_property_count = object->map()->EnumLength();
@ -6422,7 +6422,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
ASSIGN_RETURN_ON_EXCEPTION(
isolate, content,
FixedArray::UnionOfKeys(
content, GetEnumPropertyKeys(current, cache_enum_keys)),
content, JSObject::GetEnumPropertyKeys(current, cache_enum_keys)),
FixedArray);
DCHECK(ContainsOnlyValidKeys(content));

View File

@ -2069,6 +2069,9 @@ class JSObject: public JSReceiver {
// Returns the number of enumerable elements.
int GetEnumElementKeys(FixedArray* storage);
static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result);
// Returns a new map with all transitions dropped from the object's current
// map and the ElementsKind set.
static Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,

View File

@ -354,11 +354,13 @@ static inline Object* ReturnBoolean(bool value, Isolate* isolate) {
CALLSITE_GET(GetFileName, ReturnDereferencedHandle)
CALLSITE_GET(GetFunctionName, ReturnDereferencedHandle)
CALLSITE_GET(GetScriptNameOrSourceUrl, ReturnDereferencedHandle)
CALLSITE_GET(GetMethodName, ReturnDereferencedHandle)
CALLSITE_GET(GetLineNumber, ReturnPositiveSmiOrNull)
CALLSITE_GET(GetColumnNumber, ReturnPositiveSmiOrNull)
CALLSITE_GET(IsNative, ReturnBoolean)
CALLSITE_GET(IsToplevel, ReturnBoolean)
CALLSITE_GET(IsEval, ReturnBoolean)
CALLSITE_GET(IsConstructor, ReturnBoolean)
#undef CALLSITE_GET

View File

@ -291,11 +291,13 @@ namespace internal {
F(CallSiteGetFileNameRT, 3, 1) \
F(CallSiteGetFunctionNameRT, 3, 1) \
F(CallSiteGetScriptNameOrSourceUrlRT, 3, 1) \
F(CallSiteGetMethodNameRT, 3, 1) \
F(CallSiteGetLineNumberRT, 3, 1) \
F(CallSiteGetColumnNumberRT, 3, 1) \
F(CallSiteIsNativeRT, 3, 1) \
F(CallSiteIsToplevelRT, 3, 1) \
F(CallSiteIsEvalRT, 3, 1) \
F(CallSiteIsConstructorRT, 3, 1) \
F(IS_VAR, 1, 1) \
F(GetFromCache, 2, 1) \
F(IncrementStatsCounter, 1, 1) \

View File

@ -0,0 +1,20 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var o = { f: function() { throw new Error(); } };
o.g1 = function() { o.f() }
o.g2 = o.g1;
o.h = function() { o.g1() }
Error.prepareStackTrace = function(e, frames) { return frames; }
try {
o.h();
} catch (e) {
var frames = e.stack;
assertEquals("f", frames[0].getMethodName());
assertEquals(null, frames[1].getMethodName());
assertEquals("h", frames[2].getMethodName());
assertEquals(null, frames[3].getMethodName());
}