LCOV - code coverage report
Current view: top level - src/debug - debug-evaluate.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 126 131 96.2 %
Date: 2017-04-26 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/debug/debug-evaluate.h"
       6             : 
       7             : #include "src/accessors.h"
       8             : #include "src/compiler.h"
       9             : #include "src/contexts.h"
      10             : #include "src/debug/debug-frames.h"
      11             : #include "src/debug/debug-scopes.h"
      12             : #include "src/debug/debug.h"
      13             : #include "src/frames-inl.h"
      14             : #include "src/globals.h"
      15             : #include "src/interpreter/bytecode-array-iterator.h"
      16             : #include "src/interpreter/bytecodes.h"
      17             : #include "src/isolate-inl.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22          12 : static inline bool IsDebugContext(Isolate* isolate, Context* context) {
      23             :   return context->native_context() == *isolate->debug()->debug_context();
      24             : }
      25             : 
      26           6 : MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
      27             :                                           Handle<String> source) {
      28             :   // Handle the processing of break.
      29             :   DisableBreak disable_break_scope(isolate->debug());
      30             : 
      31             :   // Enter the top context from before the debugger was invoked.
      32          12 :   SaveContext save(isolate);
      33           6 :   SaveContext* top = &save;
      34          30 :   while (top != NULL && IsDebugContext(isolate, *top->context())) {
      35             :     top = top->prev();
      36             :   }
      37           6 :   if (top != NULL) isolate->set_context(*top->context());
      38             : 
      39             :   // Get the native context now set to the top context from before the
      40             :   // debugger was invoked.
      41           6 :   Handle<Context> context = isolate->native_context();
      42           6 :   Handle<JSObject> receiver(context->global_proxy());
      43             :   Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
      44          12 :   return Evaluate(isolate, outer_info, context, receiver, source, false);
      45             : }
      46             : 
      47       15579 : MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
      48             :                                          StackFrame::Id frame_id,
      49             :                                          int inlined_jsframe_index,
      50             :                                          Handle<String> source,
      51             :                                          bool throw_on_side_effect) {
      52             :   // Handle the processing of break.
      53             :   DisableBreak disable_break_scope(isolate->debug());
      54             : 
      55             :   // Get the frame where the debugging is performed.
      56       15579 :   StackTraceFrameIterator it(isolate, frame_id);
      57       15579 :   if (!it.is_javascript()) return isolate->factory()->undefined_value();
      58             :   JavaScriptFrame* frame = it.javascript_frame();
      59             : 
      60             :   // Traverse the saved contexts chain to find the active context for the
      61             :   // selected frame.
      62             :   SaveContext* save =
      63       15579 :       DebugFrameHelper::FindSavedContextForFrame(isolate, frame);
      64       31158 :   SaveContext savex(isolate);
      65             :   isolate->set_context(*(save->context()));
      66             : 
      67             :   // This is not a lot different than DebugEvaluate::Global, except that
      68             :   // variables accessible by the function we are evaluating from are
      69             :   // materialized and included on top of the native context. Changes to
      70             :   // the materialized object are written back afterwards.
      71             :   // Note that the native context is taken from the original context chain,
      72             :   // which may not be the current native context of the isolate.
      73       15579 :   ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
      74       15579 :   if (isolate->has_pending_exception()) return MaybeHandle<Object>();
      75             : 
      76             :   Handle<Context> context = context_builder.evaluation_context();
      77       15579 :   Handle<JSObject> receiver(context->global_proxy());
      78             :   MaybeHandle<Object> maybe_result =
      79             :       Evaluate(isolate, context_builder.outer_info(), context, receiver, source,
      80       31158 :                throw_on_side_effect);
      81       15579 :   if (!maybe_result.is_null()) context_builder.UpdateValues();
      82       15579 :   return maybe_result;
      83             : }
      84             : 
      85             : 
      86             : // Compile and evaluate source for the given context.
      87       15585 : MaybeHandle<Object> DebugEvaluate::Evaluate(
      88             :     Isolate* isolate, Handle<SharedFunctionInfo> outer_info,
      89             :     Handle<Context> context, Handle<Object> receiver, Handle<String> source,
      90             :     bool throw_on_side_effect) {
      91             :   Handle<JSFunction> eval_fun;
      92       31170 :   ASSIGN_RETURN_ON_EXCEPTION(
      93             :       isolate, eval_fun,
      94             :       Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
      95             :                                     NO_PARSE_RESTRICTION, kNoSourcePosition,
      96             :                                     kNoSourcePosition, kNoSourcePosition),
      97             :       Object);
      98             : 
      99             :   Handle<Object> result;
     100             :   {
     101       15469 :     NoSideEffectScope no_side_effect(isolate, throw_on_side_effect);
     102       32334 :     ASSIGN_RETURN_ON_EXCEPTION(
     103             :         isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
     104       14073 :         Object);
     105             :   }
     106             : 
     107             :   // Skip the global proxy as it has no properties and always delegates to the
     108             :   // real global object.
     109       14073 :   if (result->IsJSGlobalProxy()) {
     110          28 :     PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result));
     111             :     // TODO(verwaest): This will crash when the global proxy is detached.
     112             :     result = PrototypeIterator::GetCurrent<JSObject>(iter);
     113             :   }
     114             : 
     115             :   return result;
     116             : }
     117             : 
     118             : 
     119       15579 : DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
     120             :                                               JavaScriptFrame* frame,
     121             :                                               int inlined_jsframe_index)
     122             :     : isolate_(isolate),
     123             :       frame_(frame),
     124       47572 :       inlined_jsframe_index_(inlined_jsframe_index) {
     125       15579 :   FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
     126       15579 :   Handle<JSFunction> local_function = frame_inspector.GetFunction();
     127             :   Handle<Context> outer_context(local_function->context());
     128       15579 :   evaluation_context_ = outer_context;
     129       15579 :   outer_info_ = handle(local_function->shared());
     130             :   Factory* factory = isolate->factory();
     131             : 
     132             :   // To evaluate as if we were running eval at the point of the debug break,
     133             :   // we reconstruct the context chain as follows:
     134             :   //  - To make stack-allocated variables visible, we materialize them and
     135             :   //    use a debug-evaluate context to wrap both the materialized object and
     136             :   //    the original context.
     137             :   //  - We use the original context chain from the function context to the
     138             :   //    native context.
     139             :   //  - Between the function scope and the native context, we only resolve
     140             :   //    variable names that the current function already uses. Only for these
     141             :   //    names we can be sure that they will be correctly resolved. For the
     142             :   //    rest, we only resolve to with, script, and native contexts. We use a
     143             :   //    whitelist to implement that.
     144             :   // Context::Lookup has special handling for debug-evaluate contexts:
     145             :   //  - Look up in the materialized stack variables.
     146             :   //  - Look up in the original context.
     147             :   //  - Check the whitelist to find out whether to skip contexts during lookup.
     148             :   const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS;
     149       32306 :   for (ScopeIterator it(isolate, &frame_inspector, option); !it.Done();
     150        1148 :        it.Next()) {
     151       16694 :     ScopeIterator::ScopeType scope_type = it.Type();
     152       16694 :     if (scope_type == ScopeIterator::ScopeTypeLocal) {
     153             :       DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
     154       15266 :       Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
     155             :       Handle<Context> local_context =
     156       15266 :           it.HasContext() ? it.CurrentContext() : outer_context;
     157       15266 :       Handle<StringSet> non_locals = it.GetNonLocals();
     158             :       MaterializeReceiver(materialized, local_context, local_function,
     159       15266 :                           non_locals);
     160       15266 :       frame_inspector.MaterializeStackLocals(materialized, local_function);
     161       15266 :       MaterializeArgumentsObject(materialized, local_function);
     162             :       ContextChainElement context_chain_element;
     163       15266 :       context_chain_element.scope_info = it.CurrentScopeInfo();
     164       15266 :       context_chain_element.materialized_object = materialized;
     165             :       // Non-locals that are already being referenced by the current function
     166             :       // are guaranteed to be correctly resolved.
     167       15266 :       context_chain_element.whitelist = non_locals;
     168       15266 :       if (it.HasContext()) {
     169        1110 :         context_chain_element.wrapped_context = it.CurrentContext();
     170             :       }
     171       15266 :       context_chain_.Add(context_chain_element);
     172       15266 :       evaluation_context_ = outer_context;
     173             :       break;
     174        2856 :     } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
     175        1428 :                scope_type == ScopeIterator::ScopeTypeWith) {
     176             :       ContextChainElement context_chain_element;
     177         530 :       Handle<Context> current_context = it.CurrentContext();
     178         530 :       if (!current_context->IsDebugEvaluateContext()) {
     179         530 :         context_chain_element.wrapped_context = current_context;
     180             :       }
     181         530 :       context_chain_.Add(context_chain_element);
     182        1796 :     } else if (scope_type == ScopeIterator::ScopeTypeBlock ||
     183         898 :                scope_type == ScopeIterator::ScopeTypeEval) {
     184         618 :       Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
     185             :       frame_inspector.MaterializeStackLocals(materialized,
     186         618 :                                              it.CurrentScopeInfo());
     187             :       ContextChainElement context_chain_element;
     188         618 :       context_chain_element.scope_info = it.CurrentScopeInfo();
     189         618 :       context_chain_element.materialized_object = materialized;
     190         618 :       if (it.HasContext()) {
     191         198 :         context_chain_element.wrapped_context = it.CurrentContext();
     192             :       }
     193         618 :       context_chain_.Add(context_chain_element);
     194             :     } else {
     195             :       break;
     196             :     }
     197             :   }
     198             : 
     199       31993 :   for (int i = context_chain_.length() - 1; i >= 0; i--) {
     200             :     Handle<ScopeInfo> scope_info(ScopeInfo::CreateForWithScope(
     201       16414 :         isolate, evaluation_context_->IsNativeContext()
     202             :                      ? Handle<ScopeInfo>::null()
     203       35960 :                      : Handle<ScopeInfo>(evaluation_context_->scope_info())));
     204       16414 :     scope_info->SetIsDebugEvaluateScope();
     205             :     evaluation_context_ = factory->NewDebugEvaluateContext(
     206             :         evaluation_context_, scope_info, context_chain_[i].materialized_object,
     207       16414 :         context_chain_[i].wrapped_context, context_chain_[i].whitelist);
     208       15579 :   }
     209       15579 : }
     210             : 
     211             : 
     212       14067 : void DebugEvaluate::ContextBuilder::UpdateValues() {
     213       57890 :   for (int i = 0; i < context_chain_.length(); i++) {
     214       58701 :     ContextChainElement element = context_chain_[i];
     215       14878 :     if (!element.materialized_object.is_null()) {
     216             :       // Write back potential changes to materialized stack locals to the stack.
     217             :       FrameInspector(frame_, inlined_jsframe_index_, isolate_)
     218             :           .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
     219       14390 :                                                    element.scope_info);
     220             :     }
     221             :   }
     222       14067 : }
     223             : 
     224             : 
     225       15266 : void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject(
     226             :     Handle<JSObject> target, Handle<JSFunction> function) {
     227             :   // Do not materialize the arguments object for eval or top-level code.
     228             :   // Skip if "arguments" is already taken.
     229       15294 :   if (function->shared()->is_toplevel()) return;
     230             :   Maybe<bool> maybe = JSReceiver::HasOwnProperty(
     231       30532 :       target, isolate_->factory()->arguments_string());
     232             :   DCHECK(maybe.IsJust());
     233       15266 :   if (maybe.FromJust()) return;
     234             : 
     235             :   // FunctionGetArguments can't throw an exception.
     236       15238 :   Handle<JSObject> arguments = Accessors::FunctionGetArguments(function);
     237       15238 :   Handle<String> arguments_str = isolate_->factory()->arguments_string();
     238             :   JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
     239             :                                            NONE)
     240       30476 :       .Check();
     241             : }
     242             : 
     243       15266 : void DebugEvaluate::ContextBuilder::MaterializeReceiver(
     244             :     Handle<JSObject> target, Handle<Context> local_context,
     245             :     Handle<JSFunction> local_function, Handle<StringSet> non_locals) {
     246       15266 :   Handle<Object> recv = isolate_->factory()->undefined_value();
     247             :   Handle<String> name = isolate_->factory()->this_string();
     248       15266 :   if (non_locals->Has(name)) {
     249             :     // 'this' is allocated in an outer context and is is already being
     250             :     // referenced by the current function, so it can be correctly resolved.
     251         364 :     return;
     252       29278 :   } else if (local_function->shared()->scope_info()->HasReceiver() &&
     253       14376 :              !frame_->receiver()->IsTheHole(isolate_)) {
     254       28724 :     recv = handle(frame_->receiver(), isolate_);
     255             :   }
     256       29804 :   JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
     257             : }
     258             : 
     259             : namespace {
     260             : 
     261        3754 : bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
     262             : // Use macro to include both inlined and non-inlined version of an intrinsic.
     263             : #define INTRINSIC_WHITELIST(V)       \
     264             :   /* Conversions */                  \
     265             :   V(ToInteger)                       \
     266             :   V(ToObject)                        \
     267             :   V(ToString)                        \
     268             :   V(ToLength)                        \
     269             :   V(ToNumber)                        \
     270             :   /* Type checks */                  \
     271             :   V(IsJSReceiver)                    \
     272             :   V(IsSmi)                           \
     273             :   V(IsArray)                         \
     274             :   V(IsFunction)                      \
     275             :   V(IsDate)                          \
     276             :   V(IsJSProxy)                       \
     277             :   V(IsRegExp)                        \
     278             :   V(IsTypedArray)                    \
     279             :   V(ClassOf)                         \
     280             :   /* Loads */                        \
     281             :   V(LoadLookupSlotForCall)           \
     282             :   /* Arrays */                       \
     283             :   V(ArraySpeciesConstructor)         \
     284             :   V(NormalizeElements)               \
     285             :   V(GetArrayKeys)                    \
     286             :   V(HasComplexElements)              \
     287             :   V(EstimateNumberOfElements)        \
     288             :   /* Errors */                       \
     289             :   V(ReThrow)                         \
     290             :   V(ThrowReferenceError)             \
     291             :   V(ThrowSymbolIteratorInvalid)      \
     292             :   V(ThrowIteratorResultNotAnObject)  \
     293             :   V(NewTypeError)                    \
     294             :   /* Strings */                      \
     295             :   V(StringCharCodeAt)                \
     296             :   V(StringIndexOf)                   \
     297             :   V(StringReplaceOneCharWithString)  \
     298             :   V(SubString)                       \
     299             :   V(RegExpInternalReplace)           \
     300             :   /* Literals */                     \
     301             :   V(CreateArrayLiteral)              \
     302             :   V(CreateObjectLiteral)             \
     303             :   V(CreateRegExpLiteral)             \
     304             :   /* Collections */                  \
     305             :   V(JSCollectionGetTable)            \
     306             :   V(FixedArrayGet)                   \
     307             :   V(StringGetRawHashField)           \
     308             :   V(GenericHash)                     \
     309             :   V(MapIteratorInitialize)           \
     310             :   V(MapInitialize)                   \
     311             :   /* Called from builtins */         \
     312             :   V(StringParseFloat)                \
     313             :   V(StringParseInt)                  \
     314             :   V(StringCharCodeAtRT)              \
     315             :   V(StringIndexOfUnchecked)          \
     316             :   V(SymbolDescriptiveString)         \
     317             :   V(GenerateRandomNumbers)           \
     318             :   V(ExternalStringGetChar)           \
     319             :   V(GlobalPrint)                     \
     320             :   V(AllocateInNewSpace)              \
     321             :   V(AllocateSeqOneByteString)        \
     322             :   V(AllocateSeqTwoByteString)        \
     323             :   V(ObjectCreate)                    \
     324             :   V(ObjectHasOwnProperty)            \
     325             :   V(ArrayIndexOf)                    \
     326             :   V(ArrayIncludes_Slow)              \
     327             :   V(ArrayIsArray)                    \
     328             :   V(ThrowTypeError)                  \
     329             :   V(ThrowCalledOnNullOrUndefined)    \
     330             :   V(ThrowIncompatibleMethodReceiver) \
     331             :   V(ThrowInvalidHint)                \
     332             :   V(ThrowNotDateError)               \
     333             :   /* Misc. */                        \
     334             :   V(ForInPrepare)                    \
     335             :   V(Call)                            \
     336             :   V(MaxSmi)                          \
     337             :   V(HasInPrototypeChain)
     338             : 
     339             : #define CASE(Name)       \
     340             :   case Runtime::k##Name: \
     341             :   case Runtime::kInline##Name:
     342             : 
     343        3754 :   switch (id) {
     344             :     INTRINSIC_WHITELIST(CASE)
     345             :     return true;
     346             :     default:
     347         584 :       if (FLAG_trace_side_effect_free_debug_evaluate) {
     348             :         PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
     349           0 :                Runtime::FunctionForId(id)->name);
     350             :       }
     351             :       return false;
     352             :   }
     353             : 
     354             : #undef CASE
     355             : #undef INTRINSIC_WHITELIST
     356             : }
     357             : 
     358       99386 : bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
     359             :   typedef interpreter::Bytecode Bytecode;
     360             :   typedef interpreter::Bytecodes Bytecodes;
     361       99386 :   if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
     362       38170 :   if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
     363       31204 :   if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
     364       30472 :   if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
     365       30472 :   switch (bytecode) {
     366             :     // Whitelist for bytecodes.
     367             :     // Loads.
     368             :     case Bytecode::kLdaLookupSlot:
     369             :     case Bytecode::kLdaGlobal:
     370             :     case Bytecode::kLdaNamedProperty:
     371             :     case Bytecode::kLdaKeyedProperty:
     372             :     // Arithmetics.
     373             :     case Bytecode::kAdd:
     374             :     case Bytecode::kAddSmi:
     375             :     case Bytecode::kSub:
     376             :     case Bytecode::kSubSmi:
     377             :     case Bytecode::kMul:
     378             :     case Bytecode::kMulSmi:
     379             :     case Bytecode::kDiv:
     380             :     case Bytecode::kDivSmi:
     381             :     case Bytecode::kMod:
     382             :     case Bytecode::kModSmi:
     383             :     case Bytecode::kBitwiseAnd:
     384             :     case Bytecode::kBitwiseAndSmi:
     385             :     case Bytecode::kBitwiseOr:
     386             :     case Bytecode::kBitwiseOrSmi:
     387             :     case Bytecode::kBitwiseXor:
     388             :     case Bytecode::kBitwiseXorSmi:
     389             :     case Bytecode::kShiftLeft:
     390             :     case Bytecode::kShiftLeftSmi:
     391             :     case Bytecode::kShiftRight:
     392             :     case Bytecode::kShiftRightSmi:
     393             :     case Bytecode::kShiftRightLogical:
     394             :     case Bytecode::kShiftRightLogicalSmi:
     395             :     case Bytecode::kInc:
     396             :     case Bytecode::kDec:
     397             :     case Bytecode::kLogicalNot:
     398             :     case Bytecode::kToBooleanLogicalNot:
     399             :     case Bytecode::kTypeOf:
     400             :     // Contexts.
     401             :     case Bytecode::kCreateBlockContext:
     402             :     case Bytecode::kCreateCatchContext:
     403             :     case Bytecode::kCreateFunctionContext:
     404             :     case Bytecode::kCreateEvalContext:
     405             :     case Bytecode::kCreateWithContext:
     406             :     // Literals.
     407             :     case Bytecode::kCreateArrayLiteral:
     408             :     case Bytecode::kCreateObjectLiteral:
     409             :     case Bytecode::kCreateRegExpLiteral:
     410             :     // Allocations.
     411             :     case Bytecode::kCreateClosure:
     412             :     case Bytecode::kCreateUnmappedArguments:
     413             :     case Bytecode::kCreateRestParameter:
     414             :     // Comparisons.
     415             :     case Bytecode::kTestEqual:
     416             :     case Bytecode::kTestEqualStrict:
     417             :     case Bytecode::kTestLessThan:
     418             :     case Bytecode::kTestLessThanOrEqual:
     419             :     case Bytecode::kTestGreaterThan:
     420             :     case Bytecode::kTestGreaterThanOrEqual:
     421             :     case Bytecode::kTestInstanceOf:
     422             :     case Bytecode::kTestIn:
     423             :     case Bytecode::kTestEqualStrictNoFeedback:
     424             :     case Bytecode::kTestUndetectable:
     425             :     case Bytecode::kTestTypeOf:
     426             :     case Bytecode::kTestUndefined:
     427             :     case Bytecode::kTestNull:
     428             :     // Conversions.
     429             :     case Bytecode::kToObject:
     430             :     case Bytecode::kToNumber:
     431             :     case Bytecode::kToName:
     432             :     // Misc.
     433             :     case Bytecode::kForInPrepare:
     434             :     case Bytecode::kForInContinue:
     435             :     case Bytecode::kForInNext:
     436             :     case Bytecode::kForInStep:
     437             :     case Bytecode::kThrow:
     438             :     case Bytecode::kReThrow:
     439             :     case Bytecode::kIllegal:
     440             :     case Bytecode::kCallJSRuntime:
     441             :     case Bytecode::kStackCheck:
     442             :     case Bytecode::kReturn:
     443             :     case Bytecode::kSetPendingMessage:
     444             :       return true;
     445             :     default:
     446         446 :       if (FLAG_trace_side_effect_free_debug_evaluate) {
     447             :         PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
     448           0 :                Bytecodes::ToString(bytecode));
     449             :       }
     450             :       return false;
     451             :   }
     452             : }
     453             : 
     454        3882 : bool BuiltinHasNoSideEffect(Builtins::Name id) {
     455        3882 :   switch (id) {
     456             :     // Whitelist for builtins.
     457             :     // Object builtins.
     458             :     case Builtins::kObjectCreate:
     459             :     case Builtins::kObjectEntries:
     460             :     case Builtins::kObjectGetOwnPropertyDescriptor:
     461             :     case Builtins::kObjectGetOwnPropertyDescriptors:
     462             :     case Builtins::kObjectGetOwnPropertyNames:
     463             :     case Builtins::kObjectGetOwnPropertySymbols:
     464             :     case Builtins::kObjectGetPrototypeOf:
     465             :     case Builtins::kObjectIs:
     466             :     case Builtins::kObjectIsExtensible:
     467             :     case Builtins::kObjectIsFrozen:
     468             :     case Builtins::kObjectIsSealed:
     469             :     case Builtins::kObjectPrototypeValueOf:
     470             :     case Builtins::kObjectValues:
     471             :     case Builtins::kObjectHasOwnProperty:
     472             :     case Builtins::kObjectPrototypePropertyIsEnumerable:
     473             :     case Builtins::kObjectProtoToString:
     474             :     // Array builtins.
     475             :     case Builtins::kArrayCode:
     476             :     case Builtins::kArrayIndexOf:
     477             :     case Builtins::kArrayPrototypeValues:
     478             :     case Builtins::kArrayIncludes:
     479             :     case Builtins::kArrayPrototypeEntries:
     480             :     case Builtins::kArrayPrototypeKeys:
     481             :     case Builtins::kArrayForEach:
     482             :     case Builtins::kArrayEvery:
     483             :     case Builtins::kArraySome:
     484             :     case Builtins::kArrayReduce:
     485             :     case Builtins::kArrayReduceRight:
     486             :     // Boolean bulitins.
     487             :     case Builtins::kBooleanConstructor:
     488             :     case Builtins::kBooleanPrototypeToString:
     489             :     case Builtins::kBooleanPrototypeValueOf:
     490             :     // Date builtins.
     491             :     case Builtins::kDateConstructor:
     492             :     case Builtins::kDateNow:
     493             :     case Builtins::kDateParse:
     494             :     case Builtins::kDatePrototypeGetDate:
     495             :     case Builtins::kDatePrototypeGetDay:
     496             :     case Builtins::kDatePrototypeGetFullYear:
     497             :     case Builtins::kDatePrototypeGetHours:
     498             :     case Builtins::kDatePrototypeGetMilliseconds:
     499             :     case Builtins::kDatePrototypeGetMinutes:
     500             :     case Builtins::kDatePrototypeGetMonth:
     501             :     case Builtins::kDatePrototypeGetSeconds:
     502             :     case Builtins::kDatePrototypeGetTime:
     503             :     case Builtins::kDatePrototypeGetTimezoneOffset:
     504             :     case Builtins::kDatePrototypeGetUTCDate:
     505             :     case Builtins::kDatePrototypeGetUTCDay:
     506             :     case Builtins::kDatePrototypeGetUTCFullYear:
     507             :     case Builtins::kDatePrototypeGetUTCHours:
     508             :     case Builtins::kDatePrototypeGetUTCMilliseconds:
     509             :     case Builtins::kDatePrototypeGetUTCMinutes:
     510             :     case Builtins::kDatePrototypeGetUTCMonth:
     511             :     case Builtins::kDatePrototypeGetUTCSeconds:
     512             :     case Builtins::kDatePrototypeGetYear:
     513             :     case Builtins::kDatePrototypeToDateString:
     514             :     case Builtins::kDatePrototypeToISOString:
     515             :     case Builtins::kDatePrototypeToUTCString:
     516             :     case Builtins::kDatePrototypeToString:
     517             :     case Builtins::kDatePrototypeToTimeString:
     518             :     case Builtins::kDatePrototypeToJson:
     519             :     case Builtins::kDatePrototypeToPrimitive:
     520             :     case Builtins::kDatePrototypeValueOf:
     521             :     // Math builtins.
     522             :     case Builtins::kMathAbs:
     523             :     case Builtins::kMathAcos:
     524             :     case Builtins::kMathAcosh:
     525             :     case Builtins::kMathAsin:
     526             :     case Builtins::kMathAsinh:
     527             :     case Builtins::kMathAtan:
     528             :     case Builtins::kMathAtanh:
     529             :     case Builtins::kMathAtan2:
     530             :     case Builtins::kMathCeil:
     531             :     case Builtins::kMathCbrt:
     532             :     case Builtins::kMathExpm1:
     533             :     case Builtins::kMathClz32:
     534             :     case Builtins::kMathCos:
     535             :     case Builtins::kMathCosh:
     536             :     case Builtins::kMathExp:
     537             :     case Builtins::kMathFloor:
     538             :     case Builtins::kMathFround:
     539             :     case Builtins::kMathHypot:
     540             :     case Builtins::kMathImul:
     541             :     case Builtins::kMathLog:
     542             :     case Builtins::kMathLog1p:
     543             :     case Builtins::kMathLog2:
     544             :     case Builtins::kMathLog10:
     545             :     case Builtins::kMathMax:
     546             :     case Builtins::kMathMin:
     547             :     case Builtins::kMathPow:
     548             :     case Builtins::kMathRandom:
     549             :     case Builtins::kMathRound:
     550             :     case Builtins::kMathSign:
     551             :     case Builtins::kMathSin:
     552             :     case Builtins::kMathSinh:
     553             :     case Builtins::kMathSqrt:
     554             :     case Builtins::kMathTan:
     555             :     case Builtins::kMathTanh:
     556             :     case Builtins::kMathTrunc:
     557             :     // Number builtins.
     558             :     case Builtins::kNumberConstructor:
     559             :     case Builtins::kNumberIsFinite:
     560             :     case Builtins::kNumberIsInteger:
     561             :     case Builtins::kNumberIsNaN:
     562             :     case Builtins::kNumberIsSafeInteger:
     563             :     case Builtins::kNumberParseFloat:
     564             :     case Builtins::kNumberParseInt:
     565             :     case Builtins::kNumberPrototypeToExponential:
     566             :     case Builtins::kNumberPrototypeToFixed:
     567             :     case Builtins::kNumberPrototypeToPrecision:
     568             :     case Builtins::kNumberPrototypeToString:
     569             :     case Builtins::kNumberPrototypeValueOf:
     570             :     // String builtins. Strings are immutable.
     571             :     case Builtins::kStringFromCharCode:
     572             :     case Builtins::kStringFromCodePoint:
     573             :     case Builtins::kStringConstructor:
     574             :     case Builtins::kStringPrototypeCharAt:
     575             :     case Builtins::kStringPrototypeCharCodeAt:
     576             :     case Builtins::kStringPrototypeConcat:
     577             :     case Builtins::kStringPrototypeEndsWith:
     578             :     case Builtins::kStringPrototypeIncludes:
     579             :     case Builtins::kStringPrototypeIndexOf:
     580             :     case Builtins::kStringPrototypeLastIndexOf:
     581             :     case Builtins::kStringPrototypeStartsWith:
     582             :     case Builtins::kStringPrototypeSubstr:
     583             :     case Builtins::kStringPrototypeSubstring:
     584             :     case Builtins::kStringPrototypeToString:
     585             :     case Builtins::kStringPrototypeToLowerCase:
     586             :     case Builtins::kStringPrototypeToUpperCase:
     587             :     case Builtins::kStringPrototypeTrim:
     588             :     case Builtins::kStringPrototypeTrimLeft:
     589             :     case Builtins::kStringPrototypeTrimRight:
     590             :     case Builtins::kStringPrototypeValueOf:
     591             :     // Symbol builtins.
     592             :     case Builtins::kSymbolConstructor:
     593             :     case Builtins::kSymbolKeyFor:
     594             :     case Builtins::kSymbolPrototypeToString:
     595             :     case Builtins::kSymbolPrototypeValueOf:
     596             :     case Builtins::kSymbolPrototypeToPrimitive:
     597             :     // JSON builtins.
     598             :     case Builtins::kJsonParse:
     599             :     case Builtins::kJsonStringify:
     600             :     // Global function builtins.
     601             :     case Builtins::kGlobalDecodeURI:
     602             :     case Builtins::kGlobalDecodeURIComponent:
     603             :     case Builtins::kGlobalEncodeURI:
     604             :     case Builtins::kGlobalEncodeURIComponent:
     605             :     case Builtins::kGlobalEscape:
     606             :     case Builtins::kGlobalUnescape:
     607             :     case Builtins::kGlobalIsFinite:
     608             :     case Builtins::kGlobalIsNaN:
     609             :     // Error builtins.
     610             :     case Builtins::kMakeError:
     611             :     case Builtins::kMakeTypeError:
     612             :     case Builtins::kMakeSyntaxError:
     613             :     case Builtins::kMakeRangeError:
     614             :     case Builtins::kMakeURIError:
     615             :       return true;
     616             :     default:
     617        2100 :       if (FLAG_trace_side_effect_free_debug_evaluate) {
     618             :         PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
     619           0 :                Builtins::name(id));
     620             :       }
     621             :       return false;
     622             :   }
     623             : }
     624             : 
     625             : static const Address accessors_with_no_side_effect[] = {
     626             :     // Whitelist for accessors.
     627             :     FUNCTION_ADDR(Accessors::StringLengthGetter),
     628             :     FUNCTION_ADDR(Accessors::ArrayLengthGetter),
     629             :     FUNCTION_ADDR(Accessors::FunctionLengthGetter),
     630             :     FUNCTION_ADDR(Accessors::FunctionNameGetter),
     631             :     FUNCTION_ADDR(Accessors::BoundFunctionLengthGetter),
     632             :     FUNCTION_ADDR(Accessors::BoundFunctionNameGetter),
     633             : };
     634             : 
     635             : }  // anonymous namespace
     636             : 
     637             : // static
     638       11074 : bool DebugEvaluate::FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info) {
     639       11074 :   if (FLAG_trace_side_effect_free_debug_evaluate) {
     640             :     PrintF("[debug-evaluate] Checking function %s for side effect.\n",
     641           0 :            info->DebugName()->ToCString().get());
     642             :   }
     643             : 
     644             :   DCHECK(info->is_compiled());
     645             : 
     646       11074 :   if (info->HasBytecodeArray()) {
     647             :     // Check bytecodes against whitelist.
     648             :     Handle<BytecodeArray> bytecode_array(info->bytecode_array());
     649        6644 :     if (FLAG_trace_side_effect_free_debug_evaluate) bytecode_array->Print();
     650      115398 :     for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
     651      102110 :          it.Advance()) {
     652      103140 :       interpreter::Bytecode bytecode = it.current_bytecode();
     653             : 
     654      103140 :       if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
     655             :         Runtime::FunctionId id =
     656             :             (bytecode == interpreter::Bytecode::kInvokeIntrinsic)
     657             :                 ? it.GetIntrinsicIdOperand(0)
     658        3754 :                 : it.GetRuntimeIdOperand(0);
     659        3754 :         if (IntrinsicHasNoSideEffect(id)) continue;
     660        1030 :         return false;
     661             :       }
     662             : 
     663       99386 :       if (BytecodeHasNoSideEffect(bytecode)) continue;
     664             : 
     665             :       // Did not match whitelist.
     666             :       return false;
     667             :     }
     668        5614 :     return true;
     669             :   } else {
     670             :     // Check built-ins against whitelist.
     671             :     int builtin_index = info->code()->builtin_index();
     672        8312 :     if (builtin_index >= 0 && builtin_index < Builtins::builtin_count &&
     673        3882 :         BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) {
     674             : #ifdef DEBUG
     675             :       int mode = RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE);
     676             :       bool failed = false;
     677             :       for (RelocIterator it(info->code(), mode); !it.done(); it.next()) {
     678             :         RelocInfo* rinfo = it.rinfo();
     679             :         Address address = rinfo->target_external_reference();
     680             :         const Runtime::Function* function = Runtime::FunctionForEntry(address);
     681             :         if (function == nullptr) continue;
     682             :         if (!IntrinsicHasNoSideEffect(function->function_id)) {
     683             :           PrintF("Whitelisted builtin %s calls non-whitelisted intrinsic %s\n",
     684             :                  Builtins::name(builtin_index), function->name);
     685             :           failed = true;
     686             :         }
     687             :         CHECK(!failed);
     688             :       }
     689             : #endif  // DEBUG
     690             :       return true;
     691             :     }
     692             :   }
     693             : 
     694        2648 :   return false;
     695             : }
     696             : 
     697             : // static
     698         266 : bool DebugEvaluate::CallbackHasNoSideEffect(Address function_addr) {
     699         658 :   for (size_t i = 0; i < arraysize(accessors_with_no_side_effect); i++) {
     700         644 :     if (function_addr == accessors_with_no_side_effect[i]) return true;
     701             :   }
     702             : 
     703          14 :   if (FLAG_trace_side_effect_free_debug_evaluate) {
     704             :     PrintF("[debug-evaluate] API Callback at %p may cause side effect.\n",
     705           0 :            reinterpret_cast<void*>(function_addr));
     706             :   }
     707             :   return false;
     708             : }
     709             : 
     710             : }  // namespace internal
     711             : }  // namespace v8

Generated by: LCOV version 1.10