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:
parent
3283195d04
commit
7546302b67
@ -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,
|
||||
|
@ -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_;
|
||||
|
@ -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() {
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) \
|
||||
|
20
test/mjsunit/stack-traces-custom.js
Normal file
20
test/mjsunit/stack-traces-custom.js
Normal 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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user