text: // 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.
  
  #include "src/debug/debug-evaluate.h"
  
  #include "src/accessors.h"
  #include "src/assembler-inl.h"
  #include "src/compiler.h"
  #include "src/contexts.h"
  #include "src/debug/debug-frames.h"
  #include "src/debug/debug-scopes.h"
  #include "src/debug/debug.h"
  #include "src/frames-inl.h"
  #include "src/globals.h"
  #include "src/interpreter/bytecode-array-iterator.h"
  #include "src/interpreter/bytecodes.h"
  #include "src/isolate-inl.h"
  #include "src/snapshot/snapshot.h"
  
  namespace v8 {
  namespace internal {
  
  MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
                                            Handle<String> source,
                                            bool throw_on_side_effect) {
    // Disable breaks in side-effect free mode.
    DisableBreak disable_break_scope(isolate->debug(), throw_on_side_effect);
  
    Handle<Context> context = isolate->native_context();
    ScriptOriginOptions origin_options(false, true);
    MaybeHandle<SharedFunctionInfo> maybe_function_info =
        Compiler::GetSharedFunctionInfoForScript(
            isolate, source,
            Compiler::ScriptDetails(isolate->factory()->empty_string()),
            origin_options, nullptr, nullptr, ScriptCompiler::kNoCompileOptions,
            ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE);
  
    Handle<SharedFunctionInfo> shared_info;
    if (!maybe_function_info.ToHandle(&shared_info)) return MaybeHandle<Object>();
  
    Handle<JSFunction> fun =
        isolate->factory()->NewFunctionFromSharedFunctionInfo(shared_info,
                                                              context);
    if (throw_on_side_effect) isolate->debug()->StartSideEffectCheckMode();
    MaybeHandle<Object> result = Execution::Call(
        isolate, fun, Handle<JSObject>(context->global_proxy(), isolate), 0,
        nullptr);
    if (throw_on_side_effect) isolate->debug()->StopSideEffectCheckMode();
    return result;
  }
  
  MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
                                           StackFrame::Id frame_id,
                                           int inlined_jsframe_index,
                                           Handle<String> source,
                                           bool throw_on_side_effect) {
    // Handle the processing of break.
    DisableBreak disable_break_scope(isolate->debug());
  
    // Get the frame where the debugging is performed.
    StackTraceFrameIterator it(isolate, frame_id);
    if (!it.is_javascript()) return isolate->factory()->undefined_value();
    JavaScriptFrame* frame = it.javascript_frame();
  
    // This is not a lot different than DebugEvaluate::Global, except that
    // variables accessible by the function we are evaluating from are
    // materialized and included on top of the native context. Changes to
    // the materialized object are written back afterwards.
    // Note that the native context is taken from the original context chain,
    // which may not be the current native context of the isolate.
    ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
    if (isolate->has_pending_exception()) return MaybeHandle<Object>();
  
    Handle<Context> context = context_builder.evaluation_context();
    Handle<JSObject> receiver(context->global_proxy(), isolate);
    MaybeHandle<Object> maybe_result =
        Evaluate(isolate, context_builder.outer_info(), context, receiver, source,
                 throw_on_side_effect);
    if (!maybe_result.is_null()) context_builder.UpdateValues();
    return maybe_result;
  }
  
  MaybeHandle<Object> DebugEvaluate::WithTopmostArguments(Isolate* isolate,
                                                          Handle<String> source) {
    // Handle the processing of break.
    DisableBreak disable_break_scope(isolate->debug());
    Factory* factory = isolate->factory();
    JavaScriptFrameIterator it(isolate);
  
    // Get context and receiver.
    Handle<Context> native_context(
        Context::cast(it.frame()->context())->native_context(), isolate);
  
    // Materialize arguments as property on an extension object.
    Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
    Handle<String> arguments_str = factory->arguments_string();
    JSObject::SetOwnPropertyIgnoreAttributes(
        materialized, arguments_str,
        Accessors::FunctionGetArguments(it.frame(), 0), NONE)
        .Check();
  
    // Materialize receiver.
    Handle<String> this_str = factory->this_string();
    JSObject::SetOwnPropertyIgnoreAttributes(
        materialized, this_str, Handle<Object>(it.frame()->receiver(), isolate),
        NONE)
        .Check();
  
    // Use extension object in a debug-evaluate scope.
    Handle<ScopeInfo> scope_info =
        ScopeInfo::CreateForWithScope(isolate, Handle<ScopeInfo>::null());
    scope_info->SetIsDebugEvaluateScope();
    Handle<Context> evaluation_context =
        factory->NewDebugEvaluateContext(native_context, scope_info, materialized,
                                         Handle<Context>(), Handle<StringSet>());
    Handle<SharedFunctionInfo> outer_info(
        native_context->empty_function()->shared(), isolate);
    Handle<JSObject> receiver(native_context->global_proxy(), isolate);
    const bool throw_on_side_effect = false;
    MaybeHandle<Object> maybe_result =
        Evaluate(isolate, outer_info, evaluation_context, receiver, source,
                 throw_on_side_effect);
    return maybe_result;
  }
  
  // Compile and evaluate source for the given context.
  MaybeHandle<Object> DebugEvaluate::Evaluate(
      Isolate* isolate, Handle<SharedFunctionInfo> outer_info,
      Handle<Context> context, Handle<Object> receiver, Handle<String> source,
      bool throw_on_side_effect) {
    Handle<JSFunction> eval_fun;
    ASSIGN_RETURN_ON_EXCEPTION(
        isolate, eval_fun,
        Compiler::GetFunctionFromEval(source, outer_info, context,
                                      LanguageMode::kSloppy, NO_PARSE_RESTRICTION,
                                      kNoSourcePosition, kNoSourcePosition,
                                      kNoSourcePosition),
        Object);
  
    Handle<Object> result;
    bool success = false;
    if (throw_on_side_effect) isolate->debug()->StartSideEffectCheckMode();
    success = Execution::Call(isolate, eval_fun, receiver, 0, nullptr)
                  .ToHandle(&result);
    if (throw_on_side_effect) isolate->debug()->StopSideEffectCheckMode();
    if (!success) DCHECK(isolate->has_pending_exception());
    return success ? result : MaybeHandle<Object>();
  }
  
  Handle<SharedFunctionInfo> DebugEvaluate::ContextBuilder::outer_info() const {
    return handle(frame_inspector_.GetFunction()->shared(), isolate_);
  }
  
  DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
                                                JavaScriptFrame* frame,
                                                int inlined_jsframe_index)
      : isolate_(isolate),
        frame_inspector_(frame, inlined_jsframe_index, isolate),
        scope_iterator_(isolate, &frame_inspector_,
                        ScopeIterator::COLLECT_NON_LOCALS) {
    Handle<Context> outer_context(frame_inspector_.GetFunction()->context(),
                                  isolate);
    evaluation_context_ = outer_context;
    Factory* factory = isolate->factory();
  
    if (scope_iterator_.Done()) return;
  
    // To evaluate as if we were running eval at the point of the debug break,
    // we reconstruct the context chain as follows:
    //  - To make stack-allocated variables visible, we materialize them and
    //    use a debug-evaluate context to wrap both the materialized object and
    //    the original context.
    //  - We use the original context chain from the function context to the
    //    native context.
    //  - Between the function scope and the native context, we only resolve
    //    variable names that the current function already uses. Only for these
    //    names we can be sure that they will be correctly resolved. For the
    //    rest, we only resolve to with, script, and native contexts. We use a
    //    whitelist to implement that.
    // Context::Lookup has special handling for debug-evaluate contexts:
    //  - Look up in the materialized stack variables.
    //  - Look up in the original context.
    //  - Check the whitelist to find out whether to skip contexts during lookup.
    for (; scope_iterator_.InInnerScope(); scope_iterator_.Next()) {
      ScopeIterator::ScopeType scope_type = scope_iterator_.Type();
      if (scope_type == ScopeIterator::ScopeTypeScript) break;
      ContextChainElement context_chain_element;
      if (scope_type == ScopeIterator::ScopeTypeLocal ||
          scope_iterator_.DeclaresLocals(ScopeIterator::Mode::STACK)) {
        context_chain_element.materialized_object =
            scope_iterator_.ScopeObject(ScopeIterator::Mode::STACK);
      }
      if (scope_iterator_.HasContext()) {
        context_chain_element.wrapped_context = scope_iterator_.CurrentContext();
      }
      if (scope_type == ScopeIterator::ScopeTypeLocal) {
        context_chain_element.whitelist = scope_iterator_.GetNonLocals();
      }
      context_chain_.push_back(context_chain_element);
    }
  
    Handle<ScopeInfo> scope_info =
        evaluation_context_->IsNativeContext()
            ? Handle<ScopeInfo>::null()
            : handle(evaluation_context_->scope_info(), isolate);
    for (auto rit = context_chain_.rbegin(); rit != context_chain_.rend();
         rit++) {
      ContextChainElement element = *rit;
      scope_info = ScopeInfo::CreateForWithScope(isolate, scope_info);
      scope_info->SetIsDebugEvaluateScope();
      evaluation_context_ = factory->NewDebugEvaluateContext(
          evaluation_context_, scope_info, element.materialized_object,
          element.wrapped_context, element.whitelist);
    }
  }
  
  void DebugEvaluate::ContextBuilder::UpdateValues() {
    scope_iterator_.Restart();
    for (ContextChainElement& element : context_chain_) {
      if (!element.materialized_object.is_null()) {
        Handle<FixedArray> keys =
            KeyAccumulator::GetKeys(element.materialized_object,
                                    KeyCollectionMode::kOwnOnly,
                                    ENUMERABLE_STRINGS)
                .ToHandleChecked();
  
        for (int i = 0; i < keys->length(); i++) {
          DCHECK(keys->get(i)->IsString());
          Handle<String> key(String::cast(keys->get(i)), isolate_);
          Handle<Object> value =
              JSReceiver::GetDataProperty(element.materialized_object, key);
          scope_iterator_.SetVariableValue(key, value);
        }
      }
      scope_iterator_.Next();
    }
  }
  
  namespace {
  
  bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
  // Use macro to include only the non-inlined version of an intrinsic.
  #define INTRINSIC_WHITELIST(V)                \
    /* Conversions */                           \
    V(NumberToString)                           \
    V(ToBigInt)                                 \
    V(ToLength)                                 \
    V(ToNumber)                                 \
    V(ToObject)                                 \
    V(ToStringRT)                               \
    /* Type checks */                           \
    V(IsArray)                                  \
    V(IsFunction)                               \
    V(IsJSProxy)                                \
    V(IsJSReceiver)                             \
    V(IsRegExp)                                 \
    V(IsSmi)                                    \
    V(IsTypedArray)                             \
    /* Loads */                                 \
    V(LoadLookupSlotForCall)                    \
    V(GetProperty)                              \
    /* Arrays */                                \
    V(ArraySpeciesConstructor)                  \
    V(EstimateNumberOfElements)                 \
    V(GetArrayKeys)                             \
    V(HasComplexElements)                       \
    V(HasFastPackedElements)                    \
    V(NewArray)                                 \
    V(NormalizeElements)                        \
    V(PrepareElementsForSort)                   \
    V(TrySliceSimpleNonFastElements)            \
    V(TypedArrayGetBuffer)                      \
    /* Errors */                                \
    V(NewTypeError)                             \
    V(ReThrow)                                  \
    V(ThrowCalledNonCallable)                   \
    V(ThrowInvalidStringLength)                 \
    V(ThrowIteratorError)                       \
    V(ThrowIteratorResultNotAnObject)           \
    V(ThrowPatternAssignmentNonCoercible)       \
    V(ThrowReferenceError)                      \
    V(ThrowSymbolIteratorInvalid)               \
    /* Strings */                               \
    V(StringIncludes)                           \
    V(StringIndexOf)                            \
    V(StringReplaceOneCharWithString)           \
    V(StringSubstring)                          \
    V(StringToNumber)                           \
    V(StringTrim)                               \
    /* BigInts */                               \
    V(BigIntEqualToBigInt)                      \
    V(BigIntToBoolean)                          \
    V(BigIntToNumber)                           \
    /* Literals */                              \
    V(CreateArrayLiteral)                       \
    V(CreateArrayLiteralWithoutAllocationSite)  \
    V(CreateObjectLiteral)                      \
    V(CreateObjectLiteralWithoutAllocationSite) \
    V(CreateRegExpLiteral)                      \
    /* Called from builtins */                  \
    V(AllocateInYoungGeneration)                \
    V(AllocateInOldGeneration)                  \
    V(AllocateSeqOneByteString)                 \
    V(AllocateSeqTwoByteString)                 \
    V(ArrayIncludes_Slow)                       \
    V(ArrayIndexOf)                             \
    V(ArrayIsArray)                             \
    V(ClassOf)                                  \
    V(GetFunctionName)                          \
    V(GetOwnPropertyDescriptor)                 \
    V(GlobalPrint)                              \
    V(HasProperty)                              \
    V(ObjectCreate)                             \
    V(ObjectEntries)                            \
    V(ObjectEntriesSkipFastPath)                \
    V(ObjectHasOwnProperty)                     \
    V(ObjectValues)                             \
    V(ObjectValuesSkipFastPath)                 \
    V(ObjectGetOwnPropertyNames)                \
    V(ObjectGetOwnPropertyNamesTryFast)         \
    V(RegExpInitializeAndCompile)               \
    V(StackGuard)                               \
    V(StringAdd)                                \
    V(StringCharCodeAt)                         \
    V(StringEqual)                              \
    V(StringIndexOfUnchecked)                   \
    V(StringParseFloat)                         \
    V(StringParseInt)                           \
    V(SymbolDescriptiveString)                  \
    V(ThrowRangeError)                          \
    V(ThrowTypeError)                           \
    V(ToName)                                   \
    V(TransitionElementsKind)                   \
    /* Misc. */                                 \
    V(Call)                                     \
    V(CompleteInobjectSlackTrackingForMap)      \
    V(HasInPrototypeChain)                      \
    V(IncrementUseCounter)                      \
    V(MaxSmi)                                   \
    V(NewObject)                                \
    V(SmiLexicographicCompare)                  \
    V(StringMaxLength)                          \
    V(StringToArray)                            \
    /* Test */                                  \
    V(GetOptimizationStatus)                    \
    V(OptimizeFunctionOnNextCall)               \
    V(OptimizeOsr)                              \
    V(UnblockConcurrentRecompilation)
  
  // Intrinsics with inline versions have to be whitelisted here a second time.
  #define INLINE_INTRINSIC_WHITELIST(V) \
    V(Call)                             \
    V(IsJSReceiver)
  
  #define CASE(Name) case Runtime::k##Name:
  #define INLINE_CASE(Name) case Runtime::kInline##Name:
    switch (id) {
      INTRINSIC_WHITELIST(CASE)
      INLINE_INTRINSIC_WHITELIST(INLINE_CASE)
      return true;
      default:
        if (FLAG_trace_side_effect_free_debug_evaluate) {
          PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
                 Runtime::FunctionForId(id)->name);
        }
        return false;
    }
  
  #undef CASE
  #undef INLINE_CASE
  #undef INTRINSIC_WHITELIST
  #undef INLINE_INTRINSIC_WHITELIST
  }
  
  bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
    using interpreter::Bytecode;
    using interpreter::Bytecodes;
    if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
    if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
    if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
    if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
    switch (bytecode) {
      // Whitelist for bytecodes.
      // Loads.
      case Bytecode::kLdaLookupSlot:
      case Bytecode::kLdaGlobal:
      case Bytecode::kLdaNamedProperty:
      case Bytecode::kLdaNamedPropertyNoFeedback:
      case Bytecode::kLdaKeyedProperty:
      case Bytecode::kLdaGlobalInsideTypeof:
      case Bytecode::kLdaLookupSlotInsideTypeof:
      // Arithmetics.
      case Bytecode::kAdd:
      case Bytecode::kAddSmi:
      case Bytecode::kSub:
      case Bytecode::kSubSmi:
      case Bytecode::kMul:
      case Bytecode::kMulSmi:
      case Bytecode::kDiv:
      case Bytecode::kDivSmi:
      case Bytecode::kMod:
      case Bytecode::kModSmi:
      case Bytecode::kExp:
      case Bytecode::kExpSmi:
      case Bytecode::kNegate:
      case Bytecode::kBitwiseAnd:
      case Bytecode::kBitwiseAndSmi:
      case Bytecode::kBitwiseNot:
      case Bytecode::kBitwiseOr:
      case Bytecode::kBitwiseOrSmi:
      case Bytecode::kBitwiseXor:
      case Bytecode::kBitwiseXorSmi:
      case Bytecode::kShiftLeft:
      case Bytecode::kShiftLeftSmi:
      case Bytecode::kShiftRight:
      case Bytecode::kShiftRightSmi:
      case Bytecode::kShiftRightLogical:
      case Bytecode::kShiftRightLogicalSmi:
      case Bytecode::kInc:
      case Bytecode::kDec:
      case Bytecode::kLogicalNot:
      case Bytecode::kToBooleanLogicalNot:
      case Bytecode::kTypeOf:
      // Contexts.
      case Bytecode::kCreateBlockContext:
      case Bytecode::kCreateCatchContext:
      case Bytecode::kCreateFunctionContext:
      case Bytecode::kCreateEvalContext:
      case Bytecode::kCreateWithContext:
      // Literals.
      case Bytecode::kCreateArrayLiteral:
      case Bytecode::kCreateEmptyArrayLiteral:
      case Bytecode::kCreateArrayFromIterable:
      case Bytecode::kCreateObjectLiteral:
      case Bytecode::kCreateEmptyObjectLiteral:
      case Bytecode::kCreateRegExpLiteral:
      // Allocations.
      case Bytecode::kCreateClosure:
      case Bytecode::kCreateUnmappedArguments:
      case Bytecode::kCreateRestParameter:
      // Comparisons.
      case Bytecode::kTestEqual:
      case Bytecode::kTestEqualStrict:
      case Bytecode::kTestLessThan:
      case Bytecode::kTestLessThanOrEqual:
      case Bytecode::kTestGreaterThan:
      case Bytecode::kTestGreaterThanOrEqual:
      case Bytecode::kTestInstanceOf:
      case Bytecode::kTestIn:
      case Bytecode::kTestReferenceEqual:
      case Bytecode::kTestUndetectable:
      case Bytecode::kTestTypeOf:
      case Bytecode::kTestUndefined:
      case Bytecode::kTestNull:
      // Conversions.
      case Bytecode::kToObject:
      case Bytecode::kToName:
      case Bytecode::kToNumber:
      case Bytecode::kToNumeric:
      case Bytecode::kToString:
      // Misc.
      case Bytecode::kForInEnumerate:
      case Bytecode::kForInPrepare:
      case Bytecode::kForInContinue:
      case Bytecode::kForInNext:
      case Bytecode::kForInStep:
      case Bytecode::kThrow:
      case Bytecode::kReThrow:
      case Bytecode::kThrowReferenceErrorIfHole:
      case Bytecode::kThrowSuperNotCalledIfHole:
      case Bytecode::kThrowSuperAlreadyCalledIfNotHole:
      case Bytecode::kIllegal:
      case Bytecode::kCallJSRuntime:
      case Bytecode::kStackCheck:
      case Bytecode::kReturn:
      case Bytecode::kSetPendingMessage:
        return true;
      default:
        return false;
    }
  }
  
  DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtins::Name id) {
    switch (id) {
      // Whitelist for builtins.
      // Object builtins.
      case Builtins::kObjectConstructor:
      case Builtins::kObjectCreate:
      case Builtins::kObjectEntries:
      case Builtins::kObjectGetOwnPropertyDescriptor:
      case Builtins::kObjectGetOwnPropertyDescriptors:
      case Builtins::kObjectGetOwnPropertyNames:
      case Builtins::kObjectGetOwnPropertySymbols:
      case Builtins::kObjectGetPrototypeOf:
      case Builtins::kObjectIs:
      case Builtins::kObjectIsExtensible:
      case Builtins::kObjectIsFrozen:
      case Builtins::kObjectIsSealed:
      case Builtins::kObjectPrototypeValueOf:
      case Builtins::kObjectValues:
      case Builtins::kObjectPrototypeHasOwnProperty:
      case Builtins::kObjectPrototypeIsPrototypeOf:
      case Builtins::kObjectPrototypePropertyIsEnumerable:
      case Builtins::kObjectPrototypeToString:
      case Builtins::kObjectPrototypeToLocaleString:
      // Array builtins.
      case Builtins::kArrayIsArray:
      case Builtins::kArrayConstructor:
      case Builtins::kArrayIndexOf:
      case Builtins::kArrayPrototypeValues:
      case Builtins::kArrayIncludes:
      case Builtins::kArrayPrototypeEntries:
      case Builtins::kArrayPrototypeFill:
      case Builtins::kArrayPrototypeFind:
      case Builtins::kArrayPrototypeFindIndex:
      case Builtins::kArrayPrototypeFlat:
      case Builtins::kArrayPrototypeFlatMap:
      case Builtins::kArrayPrototypeJoin:
      case Builtins::kArrayPrototypeKeys:
      case Builtins::kArrayPrototypeLastIndexOf:
      case Builtins::kArrayPrototypeSlice:
      case Builtins::kArrayPrototypeSort:
      case Builtins::kArrayPrototypeToLocaleString:
      case Builtins::kArrayPrototypeToString:
      case Builtins::kArrayForEach:
      case Builtins::kArrayEvery:
      case Builtins::kArraySome:
      case Builtins::kArrayConcat:
      case Builtins::kArrayFilter:
      case Builtins::kArrayMap:
      case Builtins::kArrayReduce:
      case Builtins::kArrayReduceRight:
      // Trace builtins.
      case Builtins::kIsTraceCategoryEnabled:
      case Builtins::kTrace:
      // TypedArray builtins.
      case Builtins::kTypedArrayConstructor:
      case Builtins::kTypedArrayPrototypeBuffer:
      case Builtins::kTypedArrayPrototypeByteLength:
      case Builtins::kTypedArrayPrototypeByteOffset:
      case Builtins::kTypedArrayPrototypeLength:
      case Builtins::kTypedArrayPrototypeEntries:
      case Builtins::kTypedArrayPrototypeKeys:
      case Builtins::kTypedArrayPrototypeValues:
      case Builtins::kTypedArrayPrototypeFind:
      case Builtins::kTypedArrayPrototypeFindIndex:
      case Builtins::kTypedArrayPrototypeIncludes:
      case Builtins::kTypedArrayPrototypeJoin:
      case Builtins::kTypedArrayPrototypeIndexOf:
      case Builtins::kTypedArrayPrototypeLastIndexOf:
      case Builtins::kTypedArrayPrototypeSlice:
      case Builtins::kTypedArrayPrototypeSubArray:
      case Builtins::kTypedArrayPrototypeEvery:
      case Builtins::kTypedArrayPrototypeSome:
      case Builtins::kTypedArrayPrototypeToLocaleString:
      case Builtins::kTypedArrayPrototypeFilter:
      case Builtins::kTypedArrayPrototypeMap:
      case Builtins::kTypedArrayPrototypeReduce:
      case Builtins::kTypedArrayPrototypeReduceRight:
      case Builtins::kTypedArrayPrototypeForEach:
      // ArrayBuffer builtins.
      case Builtins::kArrayBufferConstructor:
      case Builtins::kArrayBufferPrototypeGetByteLength:
      case Builtins::kArrayBufferIsView:
      case Builtins::kArrayBufferPrototypeSlice:
      case Builtins::kReturnReceiver:
      // DataView builtins.
      case Builtins::kDataViewConstructor:
      case Builtins::kDataViewPrototypeGetBuffer:
      case Builtins::kDataViewPrototypeGetByteLength:
      case Builtins::kDataViewPrototypeGetByteOffset:
      case Builtins::kDataViewPrototypeGetInt8:
      case Builtins::kDataViewPrototypeGetUint8:
      case Builtins::kDataViewPrototypeGetInt16:
      case Builtins::kDataViewPrototypeGetUint16:
      case Builtins::kDataViewPrototypeGetInt32:
      case Builtins::kDataViewPrototypeGetUint32:
      case Builtins::kDataViewPrototypeGetFloat32:
      case Builtins::kDataViewPrototypeGetFloat64:
      case Builtins::kDataViewPrototypeGetBigInt64:
      case Builtins::kDataViewPrototypeGetBigUint64:
      // Boolean bulitins.
      case Builtins::kBooleanConstructor:
      case Builtins::kBooleanPrototypeToString:
      case Builtins::kBooleanPrototypeValueOf:
      // Date builtins.
      case Builtins::kDateConstructor:
      case Builtins::kDateNow:
      case Builtins::kDateParse:
      case Builtins::kDatePrototypeGetDate:
      case Builtins::kDatePrototypeGetDay:
      case Builtins::kDatePrototypeGetFullYear:
      case Builtins::kDatePrototypeGetHours:
      case Builtins::kDatePrototypeGetMilliseconds:
      case Builtins::kDatePrototypeGetMinutes:
      case Builtins::kDatePrototypeGetMonth:
      case Builtins::kDatePrototypeGetSeconds:
      case Builtins::kDatePrototypeGetTime:
      case Builtins::kDatePrototypeGetTimezoneOffset:
      case Builtins::kDatePrototypeGetUTCDate:
      case Builtins::kDatePrototypeGetUTCDay:
      case Builtins::kDatePrototypeGetUTCFullYear:
      case Builtins::kDatePrototypeGetUTCHours:
      case Builtins::kDatePrototypeGetUTCMilliseconds:
      case Builtins::kDatePrototypeGetUTCMinutes:
      case Builtins::kDatePrototypeGetUTCMonth:
      case Builtins::kDatePrototypeGetUTCSeconds:
      case Builtins::kDatePrototypeGetYear:
      case Builtins::kDatePrototypeToDateString:
      case Builtins::kDatePrototypeToISOString:
      case Builtins::kDatePrototypeToUTCString:
      case Builtins::kDatePrototypeToString:
  #ifdef V8_INTL_SUPPORT
      case Builtins::kDatePrototypeToLocaleString:
      case Builtins::kDatePrototypeToLocaleDateString:
      case Builtins::kDatePrototypeToLocaleTimeString:
  #endif
      case Builtins::kDatePrototypeToTimeString:
      case Builtins::kDatePrototypeToJson:
      case Builtins::kDatePrototypeToPrimitive:
      case Builtins::kDatePrototypeValueOf:
      // Map builtins.
      case Builtins::kMapConstructor:
      case Builtins::kMapPrototypeForEach:
      case Builtins::kMapPrototypeGet:
      case Builtins::kMapPrototypeHas:
      case Builtins::kMapPrototypeEntries:
      case Builtins::kMapPrototypeGetSize:
      case Builtins::kMapPrototypeKeys:
      case Builtins::kMapPrototypeValues:
      // WeakMap builtins.
      case Builtins::kWeakMapConstructor:
      case Builtins::kWeakMapGet:
      case Builtins::kWeakMapPrototypeHas:
      // Math builtins.
      case Builtins::kMathAbs:
      case Builtins::kMathAcos:
      case Builtins::kMathAcosh:
      case Builtins::kMathAsin:
      case Builtins::kMathAsinh:
      case Builtins::kMathAtan:
      case Builtins::kMathAtanh:
      case Builtins::kMathAtan2:
      case Builtins::kMathCeil:
      case Builtins::kMathCbrt:
      case Builtins::kMathExpm1:
      case Builtins::kMathClz32:
      case Builtins::kMathCos:
      case Builtins::kMathCosh:
      case Builtins::kMathExp:
      case Builtins::kMathFloor:
      case Builtins::kMathFround:
      case Builtins::kMathHypot:
      case Builtins::kMathImul:
      case Builtins::kMathLog:
      case Builtins::kMathLog1p:
      case Builtins::kMathLog2:
      case Builtins::kMathLog10:
      case Builtins::kMathMax:
      case Builtins::kMathMin:
      case Builtins::kMathPow:
      case Builtins::kMathRandom:
      case Builtins::kMathRound:
      case Builtins::kMathSign:
      case Builtins::kMathSin:
      case Builtins::kMathSinh:
      case Builtins::kMathSqrt:
      case Builtins::kMathTan:
      case Builtins::kMathTanh:
      case Builtins::kMathTrunc:
      // Number builtins.
      case Builtins::kNumberConstructor:
      case Builtins::kNumberIsFinite:
      case Builtins::kNumberIsInteger:
      case Builtins::kNumberIsNaN:
      case Builtins::kNumberIsSafeInteger:
      case Builtins::kNumberParseFloat:
      case Builtins::kNumberParseInt:
      case Builtins::kNumberPrototypeToExponential:
      case Builtins::kNumberPrototypeToFixed:
      case Builtins::kNumberPrototypeToPrecision:
      case Builtins::kNumberPrototypeToString:
      case Builtins::kNumberPrototypeToLocaleString:
      case Builtins::kNumberPrototypeValueOf:
      // BigInt builtins.
      case Builtins::kBigIntConstructor:
      case Builtins::kBigIntAsIntN:
      case Builtins::kBigIntAsUintN:
      case Builtins::kBigIntPrototypeToString:
      case Builtins::kBigIntPrototypeValueOf:
      // Set builtins.
      case Builtins::kSetConstructor:
      case Builtins::kSetPrototypeEntries:
      case Builtins::kSetPrototypeForEach:
      case Builtins::kSetPrototypeGetSize:
      case Builtins::kSetPrototypeHas:
      case Builtins::kSetPrototypeValues:
      // WeakSet builtins.
      case Builtins::kWeakSetConstructor:
      case Builtins::kWeakSetPrototypeHas:
      // String builtins. Strings are immutable.
      case Builtins::kStringFromCharCode:
      case Builtins::kStringFromCodePoint:
      case Builtins::kStringConstructor:
      case Builtins::kStringPrototypeAnchor:
      case Builtins::kStringPrototypeBig:
      case Builtins::kStringPrototypeBlink:
      case Builtins::kStringPrototypeBold:
      case Builtins::kStringPrototypeCharAt:
      case Builtins::kStringPrototypeCharCodeAt:
      case Builtins::kStringPrototypeCodePointAt:
      case Builtins::kStringPrototypeConcat:
      case Builtins::kStringPrototypeEndsWith:
      case Builtins::kStringPrototypeFixed:
      case Builtins::kStringPrototypeFontcolor:
      case Builtins::kStringPrototypeFontsize:
      case Builtins::kStringPrototypeIncludes:
      case Builtins::kStringPrototypeIndexOf:
      case Builtins::kStringPrototypeItalics:
      case Builtins::kStringPrototypeLastIndexOf:
      case Builtins::kStringPrototypeLink:
      case Builtins::kStringPrototypeMatchAll:
      case Builtins::kStringPrototypePadEnd:
      case Builtins::kStringPrototypePadStart:
      case Builtins::kStringPrototypeRepeat:
      case Builtins::kStringPrototypeSlice:
      case Builtins::kStringPrototypeSmall:
      case Builtins::kStringPrototypeStartsWith:
      case Builtins::kStringPrototypeStrike:
      case Builtins::kStringPrototypeSub:
      case Builtins::kStringPrototypeSubstr:
      case Builtins::kStringPrototypeSubstring:
      case Builtins::kStringPrototypeSup:
      case Builtins::kStringPrototypeToString:
  #ifndef V8_INTL_SUPPORT
      case Builtins::kStringPrototypeToLowerCase:
      case Builtins::kStringPrototypeToUpperCase:
  #endif
      case Builtins::kStringPrototypeTrim:
      case Builtins::kStringPrototypeTrimEnd:
      case Builtins::kStringPrototypeTrimStart:
      case Builtins::kStringPrototypeValueOf:
      case Builtins::kStringToNumber:
      case Builtins::kStringSubstring:
      // Symbol builtins.
      case Builtins::kSymbolConstructor:
      case Builtins::kSymbolKeyFor:
      case Builtins::kSymbolPrototypeToString:
      case Builtins::kSymbolPrototypeValueOf:
      case Builtins::kSymbolPrototypeToPrimitive:
      // JSON builtins.
      case Builtins::kJsonParse:
      case Builtins::kJsonStringify:
      // Global function builtins.
      case Builtins::kGlobalDecodeURI:
      case Builtins::kGlobalDecodeURIComponent:
      case Builtins::kGlobalEncodeURI:
      case Builtins::kGlobalEncodeURIComponent:
      case Builtins::kGlobalEscape:
      case Builtins::kGlobalUnescape:
      case Builtins::kGlobalIsFinite:
      case Builtins::kGlobalIsNaN:
      // Function builtins.
      case Builtins::kFunctionPrototypeToString:
      case Builtins::kFunctionPrototypeBind:
      case Builtins::kFastFunctionPrototypeBind:
      case Builtins::kFunctionPrototypeCall:
      case Builtins::kFunctionPrototypeApply:
      // Error builtins.
      case Builtins::kErrorConstructor:
      case Builtins::kMakeError:
      case Builtins::kMakeTypeError:
      case Builtins::kMakeSyntaxError:
      case Builtins::kMakeRangeError:
      case Builtins::kMakeURIError:
      // RegExp builtins.
      case Builtins::kRegExpConstructor:
      // Internal.
      case Builtins::kStrictPoisonPillThrower:
      case Builtins::kAllocateInYoungGeneration:
      case Builtins::kAllocateInOldGeneration:
        return DebugInfo::kHasNoSideEffect;
  
      // Set builtins.
      case Builtins::kSetIteratorPrototypeNext:
      case Builtins::kSetPrototypeAdd:
      case Builtins::kSetPrototypeClear:
      case Builtins::kSetPrototypeDelete:
      // Array builtins.
      case Builtins::kArrayIteratorPrototypeNext:
      case Builtins::kArrayPrototypePop:
      case Builtins::kArrayPrototypePush:
      case Builtins::kArrayPrototypeReverse:
      case Builtins::kArrayPrototypeShift:
      case Builtins::kArrayPrototypeUnshift:
      case Builtins::kArrayPrototypeSplice:
      case Builtins::kArrayUnshift:
      // Map builtins.
      case Builtins::kMapIteratorPrototypeNext:
      case Builtins::kMapPrototypeClear:
      case Builtins::kMapPrototypeDelete:
      case Builtins::kMapPrototypeSet:
      // RegExp builtins.
      case Builtins::kRegExpPrototypeTest:
      case Builtins::kRegExpPrototypeExec:
      case Builtins::kRegExpPrototypeSplit:
      case Builtins::kRegExpPrototypeFlagsGetter:
      case Builtins::kRegExpPrototypeGlobalGetter:
      case Builtins::kRegExpPrototypeIgnoreCaseGetter:
      case Builtins::kRegExpPrototypeMatchAll:
      case Builtins::kRegExpPrototypeMultilineGetter:
      case Builtins::kRegExpPrototypeDotAllGetter:
      case Builtins::kRegExpPrototypeUnicodeGetter:
      case Builtins::kRegExpPrototypeStickyGetter:
        return DebugInfo::kRequiresRuntimeChecks;
      default:
        if (FLAG_trace_side_effect_free_debug_evaluate) {
          PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
                 Builtins::name(id));
        }
        return DebugInfo::kHasSideEffects;
    }
  }
  
  bool BytecodeRequiresRuntimeCheck(interpreter::Bytecode bytecode) {
    using interpreter::Bytecode;
    switch (bytecode) {
      case Bytecode::kStaNamedProperty:
      case Bytecode::kStaNamedPropertyNoFeedback:
      case Bytecode::kStaNamedOwnProperty:
      case Bytecode::kStaKeyedProperty:
      case Bytecode::kStaInArrayLiteral:
      case Bytecode::kStaDataPropertyInLiteral:
      case Bytecode::kStaCurrentContextSlot:
        return true;
      default:
        return false;
    }
  }
  
  }  // anonymous namespace
  
  // static
  DebugInfo::SideEffectState DebugEvaluate::FunctionGetSideEffectState(
      Isolate* isolate, Handle<SharedFunctionInfo> info) {
    if (FLAG_trace_side_effect_free_debug_evaluate) {
      PrintF("[debug-evaluate] Checking function %s for side effect.\n",
             info->DebugName()->ToCString().get());
    }
  
    DCHECK(info->is_compiled());
    if (info->HasBytecodeArray()) {
      // Check bytecodes against whitelist.
      Handle<BytecodeArray> bytecode_array(info->GetBytecodeArray(), isolate);
      if (FLAG_trace_side_effect_free_debug_evaluate) {
        bytecode_array->Print();
      }
      bool requires_runtime_checks = false;
      for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
           it.Advance()) {
        interpreter::Bytecode bytecode = it.current_bytecode();
  
        if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
          Runtime::FunctionId id =
              (bytecode == interpreter::Bytecode::kInvokeIntrinsic)
                  ? it.GetIntrinsicIdOperand(0)
                  : it.GetRuntimeIdOperand(0);
          if (IntrinsicHasNoSideEffect(id)) continue;
          return DebugInfo::kHasSideEffects;
        }
  
        if (BytecodeHasNoSideEffect(bytecode)) continue;
        if (BytecodeRequiresRuntimeCheck(bytecode)) {
          requires_runtime_checks = true;
          continue;
        }
  
        if (FLAG_trace_side_effect_free_debug_evaluate) {
          PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
                 interpreter::Bytecodes::ToString(bytecode));
        }
  
        // Did not match whitelist.
        return DebugInfo::kHasSideEffects;
      }
      return requires_runtime_checks ? DebugInfo::kRequiresRuntimeChecks
                                     : DebugInfo::kHasNoSideEffect;
    } else if (info->IsApiFunction()) {
      if (info->GetCode()->is_builtin()) {
        return info->GetCode()->builtin_index() == Builtins::kHandleApiCall
                   ? DebugInfo::kHasNoSideEffect
                   : DebugInfo::kHasSideEffects;
      }
    } else {
      // Check built-ins against whitelist.
      int builtin_index =
          info->HasBuiltinId() ? info->builtin_id() : Builtins::kNoBuiltinId;
      if (!Builtins::IsBuiltinId(builtin_index))
        return DebugInfo::kHasSideEffects;
      DebugInfo::SideEffectState state =
          BuiltinGetSideEffectState(static_cast<Builtins::Name>(builtin_index));
      return state;
    }
  
    return DebugInfo::kHasSideEffects;
  }
  
  #ifdef DEBUG
  static bool TransitivelyCalledBuiltinHasNoSideEffect(Builtins::Name caller,
                                                       Builtins::Name callee) {
    switch (callee) {
        // Transitively called Builtins:
      case Builtins::kAbort:
      case Builtins::kAbortJS:
      case Builtins::kAdaptorWithBuiltinExitFrame:
      case Builtins::kArrayConstructorImpl:
      case Builtins::kArrayEveryLoopContinuation:
      case Builtins::kArrayFilterLoopContinuation:
      case Builtins::kArrayFindIndexLoopContinuation:
      case Builtins::kArrayFindLoopContinuation:
      case Builtins::kArrayForEachLoopContinuation:
      case Builtins::kArrayIncludesHoleyDoubles:
      case Builtins::kArrayIncludesPackedDoubles:
      case Builtins::kArrayIncludesSmiOrObject:
      case Builtins::kArrayIndexOfHoleyDoubles:
      case Builtins::kArrayIndexOfPackedDoubles:
      case Builtins::kArrayIndexOfSmiOrObject:
      case Builtins::kArrayMapLoopContinuation:
      case Builtins::kArrayReduceLoopContinuation:
      case Builtins::kArrayReduceRightLoopContinuation:
      case Builtins::kArraySomeLoopContinuation:
      case Builtins::kArrayTimSort:
      case Builtins::kCall_ReceiverIsAny:
      case Builtins::kCall_ReceiverIsNullOrUndefined:
      case Builtins::kCallWithArrayLike:
      case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
      case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit:
      case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit:
      case Builtins::kCEntry_Return1_SaveFPRegs_ArgvOnStack_NoBuiltinExit:
      case Builtins::kCEntry_Return1_SaveFPRegs_ArgvOnStack_BuiltinExit:
      case Builtins::kCEntry_Return2_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
      case Builtins::kCEntry_Return2_DontSaveFPRegs_ArgvOnStack_BuiltinExit:
      case Builtins::kCEntry_Return2_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit:
      case Builtins::kCEntry_Return2_SaveFPRegs_ArgvOnStack_NoBuiltinExit:
      case Builtins::kCEntry_Return2_SaveFPRegs_ArgvOnStack_BuiltinExit:
      case Builtins::kCloneFastJSArray:
      case Builtins::kConstruct:
      case Builtins::kConvertToLocaleString:
      case Builtins::kCreateTypedArray:
      case Builtins::kDirectCEntry:
      case Builtins::kDoubleToI:
      case Builtins::kExtractFastJSArray:
      case Builtins::kFastNewObject:
      case Builtins::kFindOrderedHashMapEntry:
      case Builtins::kFlatMapIntoArray:
      case Builtins::kFlattenIntoArray:
      case Builtins::kGetProperty:
      case Builtins::kHasProperty:
      case Builtins::kCreateHTML:
      case Builtins::kNonNumberToNumber:
      case Builtins::kNonPrimitiveToPrimitive_Number:
      case Builtins::kNumberToString:
      case Builtins::kObjectToString:
      case Builtins::kOrderedHashTableHealIndex:
      case Builtins::kOrdinaryToPrimitive_Number:
      case Builtins::kOrdinaryToPrimitive_String:
      case Builtins::kParseInt:
      case Builtins::kProxyHasProperty:
      case Builtins::kRecordWrite:
      case Builtins::kStringAdd_CheckNone:
      case Builtins::kStringEqual:
      case Builtins::kStringIndexOf:
      case Builtins::kStringRepeat:
      case Builtins::kToInteger:
      case Builtins::kToInteger_TruncateMinusZero:
      case Builtins::kToLength:
      case Builtins::kToName:
      case Builtins::kToObject:
      case Builtins::kToString:
      case Builtins::kWeakMapLookupHashIndex:
        return true;
      case Builtins::kJoinStackPop:
      case Builtins::kJoinStackPush:
        switch (caller) {
          case Builtins::kArrayPrototypeJoin:
          case Builtins::kArrayPrototypeToLocaleString:
          case Builtins::kTypedArrayPrototypeJoin:
          case Builtins::kTypedArrayPrototypeToLocaleString:
            return true;
          default:
            return false;
        }
      case Builtins::kFastCreateDataProperty:
        switch (caller) {
          case Builtins::kArrayPrototypeSlice:
          case Builtins::kArrayFilter:
            return true;
          default:
            return false;
        }
      case Builtins::kSetProperty:
        switch (caller) {
          case Builtins::kArrayPrototypeSlice:
          case Builtins::kTypedArrayPrototypeMap:
          case Builtins::kStringPrototypeMatchAll:
            return true;
          default:
            return false;
        }
      default:
        return false;
    }
  }
  
  // static
  void DebugEvaluate::VerifyTransitiveBuiltins(Isolate* isolate) {
    // TODO(yangguo): also check runtime calls.
    bool failed = false;
    bool sanity_check = false;
    for (int i = 0; i < Builtins::builtin_count; i++) {
      Builtins::Name caller = static_cast<Builtins::Name>(i);
      DebugInfo::SideEffectState state = BuiltinGetSideEffectState(caller);
      if (state != DebugInfo::kHasNoSideEffect) continue;
      Code code = isolate->builtins()->builtin(caller);
      int mode = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
                 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET);
  
      for (RelocIterator it(code, mode); !it.done(); it.next()) {
        RelocInfo* rinfo = it.rinfo();
        DCHECK(RelocInfo::IsCodeTargetMode(rinfo->rmode()));
        Code callee_code = isolate->heap()->GcSafeFindCodeForInnerPointer(
            rinfo->target_address());
        if (!callee_code->is_builtin()) continue;
        Builtins::Name callee =
            static_cast<Builtins::Name>(callee_code->builtin_index());
        if (BuiltinGetSideEffectState(callee) == DebugInfo::kHasNoSideEffect) {
          continue;
        }
        if (TransitivelyCalledBuiltinHasNoSideEffect(caller, callee)) {
          sanity_check = true;
          continue;
        }
        PrintF("Whitelisted builtin %s calls non-whitelisted builtin %s\n",
               Builtins::name(caller), Builtins::name(callee));
        failed = true;
      }
    }
    CHECK(!failed);
  #if defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_MIPS64)
    // Isolate-independent builtin calls and jumps do not emit reloc infos
    // on PPC. We try to avoid using PC relative code due to performance
    // issue with especially older hardwares.
    // MIPS64 doesn't have PC relative code currently.
    // TODO(mips): Add PC relative code to MIPS64.
    USE(sanity_check);
  #else
    CHECK(sanity_check);
  #endif
  }
  #endif  // DEBUG
  
  // static
  void DebugEvaluate::ApplySideEffectChecks(
      Handle<BytecodeArray> bytecode_array) {
    for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
         it.Advance()) {
      interpreter::Bytecode bytecode = it.current_bytecode();
      if (BytecodeRequiresRuntimeCheck(bytecode)) it.ApplyDebugBreak();
    }
  }
  
  }  // namespace internal
  }  // namespace v8
  