Commit 6a833f23 authored by yangguo's avatar yangguo Committed by Commit bot

[debug] additional checks for built-ins calling runtime functions.

R=jgruber@chromium.org
BUG=v8:5821

Review-Url: https://codereview.chromium.org/2841513002
Cr-Commit-Position: refs/heads/master@{#44796}
parent e8f1fc24
...@@ -260,58 +260,80 @@ namespace { ...@@ -260,58 +260,80 @@ namespace {
bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) { bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
// Use macro to include both inlined and non-inlined version of an intrinsic. // Use macro to include both inlined and non-inlined version of an intrinsic.
#define INTRINSIC_WHITELIST(V) \ #define INTRINSIC_WHITELIST(V) \
/* Conversions */ \ /* Conversions */ \
V(ToInteger) \ V(ToInteger) \
V(ToObject) \ V(ToObject) \
V(ToString) \ V(ToString) \
V(ToLength) \ V(ToLength) \
V(ToNumber) \ V(ToNumber) \
/* Type checks */ \ /* Type checks */ \
V(IsJSReceiver) \ V(IsJSReceiver) \
V(IsSmi) \ V(IsSmi) \
V(IsArray) \ V(IsArray) \
V(IsFunction) \ V(IsFunction) \
V(IsDate) \ V(IsDate) \
V(IsJSProxy) \ V(IsJSProxy) \
V(IsRegExp) \ V(IsRegExp) \
V(IsTypedArray) \ V(IsTypedArray) \
V(ClassOf) \ V(ClassOf) \
/* Loads */ \ /* Loads */ \
V(LoadLookupSlotForCall) \ V(LoadLookupSlotForCall) \
/* Arrays */ \ /* Arrays */ \
V(ArraySpeciesConstructor) \ V(ArraySpeciesConstructor) \
V(NormalizeElements) \ V(NormalizeElements) \
V(GetArrayKeys) \ V(GetArrayKeys) \
V(HasComplexElements) \ V(HasComplexElements) \
V(EstimateNumberOfElements) \ V(EstimateNumberOfElements) \
/* Errors */ \ /* Errors */ \
V(ReThrow) \ V(ReThrow) \
V(ThrowReferenceError) \ V(ThrowReferenceError) \
V(ThrowSymbolIteratorInvalid) \ V(ThrowSymbolIteratorInvalid) \
V(ThrowIteratorResultNotAnObject) \ V(ThrowIteratorResultNotAnObject) \
V(NewTypeError) \ V(NewTypeError) \
/* Strings */ \ /* Strings */ \
V(StringCharCodeAt) \ V(StringCharCodeAt) \
V(StringIndexOf) \ V(StringIndexOf) \
V(StringReplaceOneCharWithString) \ V(StringReplaceOneCharWithString) \
V(SubString) \ V(SubString) \
V(RegExpInternalReplace) \ V(RegExpInternalReplace) \
/* Literals */ \ /* Literals */ \
V(CreateArrayLiteral) \ V(CreateArrayLiteral) \
V(CreateObjectLiteral) \ V(CreateObjectLiteral) \
V(CreateRegExpLiteral) \ V(CreateRegExpLiteral) \
/* Collections */ \ /* Collections */ \
V(JSCollectionGetTable) \ V(JSCollectionGetTable) \
V(FixedArrayGet) \ V(FixedArrayGet) \
V(StringGetRawHashField) \ V(StringGetRawHashField) \
V(GenericHash) \ V(GenericHash) \
V(MapIteratorInitialize) \ V(MapIteratorInitialize) \
V(MapInitialize) \ V(MapInitialize) \
/* Misc. */ \ /* Called from builtins */ \
V(ForInPrepare) \ V(StringParseFloat) \
V(Call) \ V(StringParseInt) \
V(MaxSmi) \ V(StringCharCodeAtRT) \
V(StringIndexOfUnchecked) \
V(SymbolDescriptiveString) \
V(GenerateRandomNumbers) \
V(ExternalStringGetChar) \
V(GlobalPrint) \
V(AllocateInNewSpace) \
V(AllocateSeqOneByteString) \
V(AllocateSeqTwoByteString) \
V(ObjectCreate) \
V(ObjectHasOwnProperty) \
V(ArrayIndexOf) \
V(ArrayIncludes_Slow) \
V(ArrayIsArray) \
V(ThrowTypeError) \
V(ThrowCalledOnNullOrUndefined) \
V(ThrowIncompatibleMethodReceiver) \
V(ThrowInvalidHint) \
V(ThrowNotDateError) \
/* Misc. */ \
V(ForInPrepare) \
V(Call) \
V(MaxSmi) \
V(HasInPrototypeChain) V(HasInPrototypeChain)
#define CASE(Name) \ #define CASE(Name) \
...@@ -649,6 +671,22 @@ bool DebugEvaluate::FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info) { ...@@ -649,6 +671,22 @@ bool DebugEvaluate::FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info) {
int builtin_index = info->code()->builtin_index(); int builtin_index = info->code()->builtin_index();
if (builtin_index >= 0 && builtin_index < Builtins::builtin_count && if (builtin_index >= 0 && builtin_index < Builtins::builtin_count &&
BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) { BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) {
#ifdef DEBUG
int mode = RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE);
bool failed = false;
for (RelocIterator it(info->code(), mode); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address address = rinfo->target_external_reference();
const Runtime::Function* function = Runtime::FunctionForEntry(address);
if (function == nullptr) continue;
if (!IntrinsicHasNoSideEffect(function->function_id)) {
PrintF("Whitelisted builtin %s calls non-whitelisted intrinsic %s\n",
Builtins::name(builtin_index), function->name);
failed = true;
}
CHECK(!failed);
}
#endif // DEBUG
return true; return true;
} }
} }
......
...@@ -6712,3 +6712,29 @@ TEST(DebugGetPossibleBreakpointsReturnLocations) { ...@@ -6712,3 +6712,29 @@ TEST(DebugGetPossibleBreakpointsReturnLocations) {
CHECK(returns_count == 1); CHECK(returns_count == 1);
} }
} }
TEST(DebugEvaluateNoSideEffect) {
LocalContext env;
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
i::List<i::Handle<i::JSFunction>> list;
{
i::HeapIterator iterator(isolate->heap());
while (i::HeapObject* obj = iterator.next()) {
if (!obj->IsJSFunction()) continue;
i::JSFunction* fun = i::JSFunction::cast(obj);
list.Add(i::Handle<i::JSFunction>(fun));
}
}
// Perform side effect check on all built-in functions. The side effect check
// itself contains additional sanity checks.
for (i::Handle<i::JSFunction> fun : list) {
bool failed = false;
{
i::NoSideEffectScope scope(isolate, true);
failed = !isolate->debug()->PerformSideEffectCheck(fun);
}
if (failed) isolate->clear_pending_exception();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment