debug-evaluate.cc 37.3 KB
Newer Older
1 2 3 4 5 6 7
// 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"
8
#include "src/assembler-inl.h"
9
#include "src/compiler.h"
10 11 12
#include "src/contexts.h"
#include "src/debug/debug-frames.h"
#include "src/debug/debug-scopes.h"
yangguo's avatar
yangguo committed
13
#include "src/debug/debug.h"
14
#include "src/frames-inl.h"
yangguo's avatar
yangguo committed
15
#include "src/globals.h"
16 17
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecodes.h"
18
#include "src/isolate-inl.h"
19
#include "src/snapshot/snapshot.h"
20 21 22 23

namespace v8 {
namespace internal {

24
MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
25 26
                                          Handle<String> source,
                                          bool throw_on_side_effect) {
27
  Handle<Context> context = isolate->native_context();
28 29 30
  ScriptOriginOptions origin_options(false, true);
  MaybeHandle<SharedFunctionInfo> maybe_function_info =
      Compiler::GetSharedFunctionInfoForScript(
31 32 33
          source, Compiler::ScriptDetails(isolate->factory()->empty_string()),
          origin_options, nullptr, nullptr, ScriptCompiler::kNoCompileOptions,
          ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE);
34 35 36 37 38 39 40

  Handle<SharedFunctionInfo> shared_info;
  if (!maybe_function_info.ToHandle(&shared_info)) return MaybeHandle<Object>();

  Handle<JSFunction> fun =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(shared_info,
                                                            context);
41
  NoSideEffectScope no_side_effect(isolate, throw_on_side_effect);
42 43
  return Execution::Call(isolate, fun,
                         Handle<JSObject>(context->global_proxy()), 0, nullptr);
44 45 46 47 48
}

MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
                                         StackFrame::Id frame_id,
                                         int inlined_jsframe_index,
49 50
                                         Handle<String> source,
                                         bool throw_on_side_effect) {
51
  // Handle the processing of break.
52
  DisableBreak disable_break_scope(isolate->debug());
53 54

  // Get the frame where the debugging is performed.
55 56 57
  StackTraceFrameIterator it(isolate, frame_id);
  if (!it.is_javascript()) return isolate->factory()->undefined_value();
  JavaScriptFrame* frame = it.javascript_frame();
58

59 60 61 62
  // 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.
63 64
  // Note that the native context is taken from the original context chain,
  // which may not be the current native context of the isolate.
65 66 67
  ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
  if (isolate->has_pending_exception()) return MaybeHandle<Object>();

68
  Handle<Context> context = context_builder.evaluation_context();
69
  Handle<JSObject> receiver(context->global_proxy());
70 71 72
  MaybeHandle<Object> maybe_result =
      Evaluate(isolate, context_builder.outer_info(), context, receiver, source,
               throw_on_side_effect);
73
  if (!maybe_result.is_null()) context_builder.UpdateValues();
74 75 76
  return maybe_result;
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
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->closure()->shared(),
                                        isolate);
  Handle<JSObject> receiver(native_context->global_proxy());
  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;
}
119 120 121 122

// Compile and evaluate source for the given context.
MaybeHandle<Object> DebugEvaluate::Evaluate(
    Isolate* isolate, Handle<SharedFunctionInfo> outer_info,
123 124
    Handle<Context> context, Handle<Object> receiver, Handle<String> source,
    bool throw_on_side_effect) {
125
  Handle<JSFunction> eval_fun;
126 127
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, eval_fun,
128 129 130 131
      Compiler::GetFunctionFromEval(source, outer_info, context,
                                    LanguageMode::kSloppy, NO_PARSE_RESTRICTION,
                                    kNoSourcePosition, kNoSourcePosition,
                                    kNoSourcePosition),
132
      Object);
133 134

  Handle<Object> result;
135
  {
136
    NoSideEffectScope no_side_effect(isolate, throw_on_side_effect);
137
    ASSIGN_RETURN_ON_EXCEPTION(
138 139
        isolate, result,
        Execution::Call(isolate, eval_fun, receiver, 0, nullptr), Object);
140
  }
141 142 143 144

  // Skip the global proxy as it has no properties and always delegates to the
  // real global object.
  if (result->IsJSGlobalProxy()) {
145
    PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result));
146
    // TODO(verwaest): This will crash when the global proxy is detached.
147
    result = PrototypeIterator::GetCurrent<JSObject>(iter);
148 149 150 151 152 153 154 155 156 157 158 159 160
  }

  return result;
}


DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
                                              JavaScriptFrame* frame,
                                              int inlined_jsframe_index)
    : isolate_(isolate),
      frame_(frame),
      inlined_jsframe_index_(inlined_jsframe_index) {
  FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
161
  Handle<JSFunction> local_function = frame_inspector.GetFunction();
162
  Handle<Context> outer_context(local_function->context());
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
  evaluation_context_ = outer_context;
  outer_info_ = handle(local_function->shared());
  Factory* factory = isolate->factory();

  // 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.
183
  const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS;
184 185
  for (ScopeIterator it(isolate, &frame_inspector, option); !it.Done();
       it.Next()) {
186 187
    ScopeIterator::ScopeType scope_type = it.Type();
    if (scope_type == ScopeIterator::ScopeTypeLocal) {
188
      DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
189
      Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
190
      Handle<Context> local_context =
191
          it.HasContext() ? it.CurrentContext() : outer_context;
192 193 194
      Handle<StringSet> non_locals = it.GetNonLocals();
      MaterializeReceiver(materialized, local_context, local_function,
                          non_locals);
195
      MaterializeStackLocals(materialized, local_function, &frame_inspector);
196 197
      ContextChainElement context_chain_element;
      context_chain_element.scope_info = it.CurrentScopeInfo();
198 199 200 201 202 203 204
      context_chain_element.materialized_object = materialized;
      // Non-locals that are already being referenced by the current function
      // are guaranteed to be correctly resolved.
      context_chain_element.whitelist = non_locals;
      if (it.HasContext()) {
        context_chain_element.wrapped_context = it.CurrentContext();
      }
205
      context_chain_.push_back(context_chain_element);
206 207
      evaluation_context_ = outer_context;
      break;
208
    } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
209 210
               scope_type == ScopeIterator::ScopeTypeWith ||
               scope_type == ScopeIterator::ScopeTypeModule) {
211
      ContextChainElement context_chain_element;
212 213 214 215
      Handle<Context> current_context = it.CurrentContext();
      if (!current_context->IsDebugEvaluateContext()) {
        context_chain_element.wrapped_context = current_context;
      }
216
      context_chain_.push_back(context_chain_element);
217 218
    } else if (scope_type == ScopeIterator::ScopeTypeBlock ||
               scope_type == ScopeIterator::ScopeTypeEval) {
219
      Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
220
      frame_inspector.MaterializeStackLocals(materialized,
221
                                             it.CurrentScopeInfo());
222 223 224
      ContextChainElement context_chain_element;
      context_chain_element.scope_info = it.CurrentScopeInfo();
      context_chain_element.materialized_object = materialized;
225
      if (it.HasContext()) {
226
        context_chain_element.wrapped_context = it.CurrentContext();
227
      }
228
      context_chain_.push_back(context_chain_element);
229
    } else {
230
      break;
231 232
    }
  }
233

234 235 236
  for (auto rit = context_chain_.rbegin(); rit != context_chain_.rend();
       rit++) {
    ContextChainElement element = *rit;
237 238 239 240 241
    Handle<ScopeInfo> scope_info(ScopeInfo::CreateForWithScope(
        isolate, evaluation_context_->IsNativeContext()
                     ? Handle<ScopeInfo>::null()
                     : Handle<ScopeInfo>(evaluation_context_->scope_info())));
    scope_info->SetIsDebugEvaluateScope();
242
    evaluation_context_ = factory->NewDebugEvaluateContext(
243 244
        evaluation_context_, scope_info, element.materialized_object,
        element.wrapped_context, element.whitelist);
245 246 247 248 249
  }
}


void DebugEvaluate::ContextBuilder::UpdateValues() {
250
  for (ContextChainElement& element : context_chain_) {
251
    if (!element.materialized_object.is_null()) {
252
      // Write back potential changes to materialized stack locals to the stack.
253 254 255 256 257 258 259 260
      FrameInspector(frame_, inlined_jsframe_index_, isolate_)
          .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
                                                   element.scope_info);
    }
  }
}


261 262 263 264 265 266 267 268 269
void DebugEvaluate::ContextBuilder::MaterializeReceiver(
    Handle<JSObject> target, Handle<Context> local_context,
    Handle<JSFunction> local_function, Handle<StringSet> non_locals) {
  Handle<Object> recv = isolate_->factory()->undefined_value();
  Handle<String> name = isolate_->factory()->this_string();
  if (non_locals->Has(name)) {
    // 'this' is allocated in an outer context and is is already being
    // referenced by the current function, so it can be correctly resolved.
    return;
270
  } else if (local_function->shared()->scope_info()->HasReceiver() &&
271
             !frame_->receiver()->IsTheHole(isolate_)) {
272
    recv = handle(frame_->receiver(), isolate_);
273
  }
274
  JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
275 276
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
void DebugEvaluate::ContextBuilder::MaterializeStackLocals(
    Handle<JSObject> target, Handle<JSFunction> function,
    FrameInspector* frame_inspector) {
  bool materialize_arguments_object = true;

  // Do not materialize the arguments object for eval or top-level code.
  if (function->shared()->is_toplevel()) materialize_arguments_object = false;

  // First materialize stack locals (modulo arguments object).
  Handle<SharedFunctionInfo> shared(function->shared());
  Handle<ScopeInfo> scope_info(shared->scope_info());
  frame_inspector->MaterializeStackLocals(target, scope_info,
                                          materialize_arguments_object);

  // Then materialize the arguments object.
  if (materialize_arguments_object) {
    // Skip if "arguments" is already taken and wasn't optimized out (which
    // causes {MaterializeStackLocals} above to skip the local variable).
    Handle<String> arguments_str = isolate_->factory()->arguments_string();
    Maybe<bool> maybe = JSReceiver::HasOwnProperty(target, arguments_str);
    DCHECK(maybe.IsJust());
    if (maybe.FromJust()) return;

    // FunctionGetArguments can't throw an exception.
    Handle<JSObject> arguments =
        Accessors::FunctionGetArguments(frame_, inlined_jsframe_index_);
    JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
                                             NONE)
        .Check();
  }
}

309 310 311
namespace {

bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
312
// Use macro to include both inlined and non-inlined version of an intrinsic.
313 314
#define INTRINSIC_WHITELIST(V)           \
  /* Conversions */                      \
315 316
  V(NumberToStringSkipCache)             \
  V(ToBigInt)                            \
317 318 319
  V(ToInteger)                           \
  V(ToLength)                            \
  V(ToNumber)                            \
320 321
  V(ToObject)                            \
  V(ToString)                            \
322 323 324
  /* Type checks */                      \
  V(IsArray)                             \
  V(IsDate)                              \
325
  V(IsFunction)                          \
326
  V(IsJSMap)                             \
327 328
  V(IsJSProxy)                           \
  V(IsJSReceiver)                        \
329 330 331 332
  V(IsJSSet)                             \
  V(IsJSWeakMap)                         \
  V(IsJSWeakSet)                         \
  V(IsRegExp)                            \
333
  V(IsSmi)                               \
334 335 336 337 338
  V(IsTypedArray)                        \
  /* Loads */                            \
  V(LoadLookupSlotForCall)               \
  /* Arrays */                           \
  V(ArraySpeciesConstructor)             \
339
  V(EstimateNumberOfElements)            \
340 341
  V(GetArrayKeys)                        \
  V(HasComplexElements)                  \
342
  V(NewArray)                            \
343 344
  V(NormalizeElements)                   \
  V(TrySliceSimpleNonFastElements)       \
345
  V(TypedArrayGetBuffer)                 \
346
  /* Errors */                           \
347
  V(NewTypeError)                        \
348
  V(ReThrow)                             \
349 350 351
  V(ThrowCalledNonCallable)              \
  V(ThrowInvalidStringLength)            \
  V(ThrowIteratorResultNotAnObject)      \
352 353 354
  V(ThrowReferenceError)                 \
  V(ThrowSymbolIteratorInvalid)          \
  /* Strings */                          \
355
  V(RegExpInternalReplace)               \
356
  V(StringIncludes)                      \
357
  V(StringIndexOf)                       \
358
  V(StringReplaceOneCharWithString)      \
359
  V(StringSubstring)                     \
360 361 362 363 364 365 366 367 368 369 370 371
  V(StringToNumber)                      \
  V(StringTrim)                          \
  /* BigInts */                          \
  V(BigIntEqualToBigInt)                 \
  V(BigIntToBoolean)                     \
  V(BigIntToNumber)                      \
  /* Literals */                         \
  V(CreateArrayLiteral)                  \
  V(CreateObjectLiteral)                 \
  V(CreateRegExpLiteral)                 \
  /* Called from builtins */             \
  V(AllocateInNewSpace)                  \
372
  V(AllocateInTargetSpace)               \
373 374
  V(AllocateSeqOneByteString)            \
  V(AllocateSeqTwoByteString)            \
375 376 377 378 379 380 381 382 383
  V(ArrayIncludes_Slow)                  \
  V(ArrayIndexOf)                        \
  V(ArrayIsArray)                        \
  V(ClassOf)                             \
  V(GenerateRandomNumbers)               \
  V(GetFunctionName)                     \
  V(GetOwnPropertyDescriptor)            \
  V(GlobalPrint)                         \
  V(HasProperty)                         \
384
  V(ObjectCreate)                        \
385 386
  V(ObjectEntries)                       \
  V(ObjectEntriesSkipFastPath)           \
387
  V(ObjectHasOwnProperty)                \
388 389
  V(ObjectValues)                        \
  V(ObjectValuesSkipFastPath)            \
390 391 392 393 394 395 396 397 398
  V(RegExpInitializeAndCompile)          \
  V(StackGuard)                          \
  V(StringAdd)                           \
  V(StringCharCodeAt)                    \
  V(StringEqual)                         \
  V(StringIndexOfUnchecked)              \
  V(StringParseFloat)                    \
  V(StringParseInt)                      \
  V(SymbolDescriptiveString)             \
399
  V(ThrowRangeError)                     \
400
  V(ThrowTypeError)                      \
401 402 403 404 405
  V(ToName)                              \
  /* Misc. */                            \
  V(Call)                                \
  V(CompleteInobjectSlackTrackingForMap) \
  V(HasInPrototypeChain)                 \
406 407
  V(MaxSmi)                              \
  V(NewObject)                           \
408 409
  V(StringMaxLength)                     \
  /* Test */                             \
410
  V(GetOptimizationStatus)               \
411
  V(OptimizeFunctionOnNextCall)          \
412 413
  V(OptimizeOsr)                         \
  V(UnblockConcurrentRecompilation)
414 415 416 417 418

#define CASE(Name)       \
  case Runtime::k##Name: \
  case Runtime::kInline##Name:

419
  switch (id) {
420 421
    INTRINSIC_WHITELIST(CASE)
    return true;
422 423
    default:
      if (FLAG_trace_side_effect_free_debug_evaluate) {
424
        PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
425 426 427 428
               Runtime::FunctionForId(id)->name);
      }
      return false;
  }
429 430 431

#undef CASE
#undef INTRINSIC_WHITELIST
432 433
}

434 435 436 437 438 439 440 441 442 443 444 445 446
#ifdef DEBUG
bool BuiltinToIntrinsicHasNoSideEffect(Builtins::Name builtin_id,
                                       Runtime::FunctionId intrinsic_id) {
  // First check the intrinsic whitelist.
  if (IntrinsicHasNoSideEffect(intrinsic_id)) return true;

// Whitelist intrinsics called from specific builtins.
#define BUILTIN_INTRINSIC_WHITELIST(V, W)                                 \
  /* Arrays */                                                            \
  V(Builtins::kArrayFilter, W(CreateDataProperty))                        \
  V(Builtins::kArrayMap, W(CreateDataProperty))                           \
  V(Builtins::kArrayPrototypeSlice, W(CreateDataProperty) W(SetProperty)) \
  /* TypedArrays */                                                       \
447
  V(Builtins::kTypedArrayConstructor,                                     \
448
    W(TypedArrayCopyElements) W(ThrowInvalidTypedArrayAlignment))         \
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
  V(Builtins::kTypedArrayPrototypeFilter, W(TypedArrayCopyElements))      \
  V(Builtins::kTypedArrayPrototypeMap, W(SetProperty))

#define CASE(Builtin, ...) \
  case Builtin:            \
    return (__VA_ARGS__ false);

#define MATCH(Intrinsic)                   \
  intrinsic_id == Runtime::k##Intrinsic || \
      intrinsic_id == Runtime::kInline##Intrinsic ||

  switch (builtin_id) {
    BUILTIN_INTRINSIC_WHITELIST(CASE, MATCH)
    default:
      return false;
  }

#undef MATCH
#undef CASE
#undef BUILTIN_INTRINSIC_WHITELIST
}
#endif  // DEBUG

472 473 474 475
bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
  typedef interpreter::Bytecode Bytecode;
  typedef interpreter::Bytecodes Bytecodes;
  if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
476
  if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
477 478
  if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
  if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
479 480
  switch (bytecode) {
    // Whitelist for bytecodes.
481
    // Loads.
482 483 484 485
    case Bytecode::kLdaLookupSlot:
    case Bytecode::kLdaGlobal:
    case Bytecode::kLdaNamedProperty:
    case Bytecode::kLdaKeyedProperty:
486
    // Arithmetics.
487
    case Bytecode::kAdd:
488 489 490 491
    case Bytecode::kAddSmi:
    case Bytecode::kSub:
    case Bytecode::kSubSmi:
    case Bytecode::kMul:
492
    case Bytecode::kMulSmi:
493
    case Bytecode::kDiv:
494
    case Bytecode::kDivSmi:
495
    case Bytecode::kMod:
496
    case Bytecode::kModSmi:
497 498
    case Bytecode::kExp:
    case Bytecode::kExpSmi:
499
    case Bytecode::kNegate:
500 501
    case Bytecode::kBitwiseAnd:
    case Bytecode::kBitwiseAndSmi:
502
    case Bytecode::kBitwiseNot:
503 504 505
    case Bytecode::kBitwiseOr:
    case Bytecode::kBitwiseOrSmi:
    case Bytecode::kBitwiseXor:
506
    case Bytecode::kBitwiseXorSmi:
507 508 509 510 511
    case Bytecode::kShiftLeft:
    case Bytecode::kShiftLeftSmi:
    case Bytecode::kShiftRight:
    case Bytecode::kShiftRightSmi:
    case Bytecode::kShiftRightLogical:
512
    case Bytecode::kShiftRightLogicalSmi:
513 514 515 516 517 518 519
    case Bytecode::kInc:
    case Bytecode::kDec:
    case Bytecode::kLogicalNot:
    case Bytecode::kToBooleanLogicalNot:
    case Bytecode::kTypeOf:
    // Contexts.
    case Bytecode::kCreateBlockContext:
520
    case Bytecode::kCreateCatchContext:
521 522 523 524 525
    case Bytecode::kCreateFunctionContext:
    case Bytecode::kCreateEvalContext:
    case Bytecode::kCreateWithContext:
    // Literals.
    case Bytecode::kCreateArrayLiteral:
526
    case Bytecode::kCreateEmptyArrayLiteral:
527
    case Bytecode::kCreateObjectLiteral:
528
    case Bytecode::kCreateEmptyObjectLiteral:
529
    case Bytecode::kCreateRegExpLiteral:
530 531
    // Allocations.
    case Bytecode::kCreateClosure:
532
    case Bytecode::kCreateUnmappedArguments:
533
    case Bytecode::kCreateRestParameter:
534 535 536 537 538 539 540 541 542 543 544 545 546 547
    // 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::kTestEqualStrictNoFeedback:
    case Bytecode::kTestUndetectable:
    case Bytecode::kTestTypeOf:
    case Bytecode::kTestUndefined:
    case Bytecode::kTestNull:
548 549
    // Conversions.
    case Bytecode::kToObject:
550
    case Bytecode::kToNumber:
551
    case Bytecode::kToName:
552
    case Bytecode::kToString:
553
    // Misc.
554
    case Bytecode::kForInEnumerate:
555 556 557 558
    case Bytecode::kForInPrepare:
    case Bytecode::kForInContinue:
    case Bytecode::kForInNext:
    case Bytecode::kForInStep:
559
    case Bytecode::kThrow:
560
    case Bytecode::kReThrow:
561 562 563
    case Bytecode::kThrowReferenceErrorIfHole:
    case Bytecode::kThrowSuperNotCalledIfHole:
    case Bytecode::kThrowSuperAlreadyCalledIfNotHole:
564 565 566 567
    case Bytecode::kIllegal:
    case Bytecode::kCallJSRuntime:
    case Bytecode::kStackCheck:
    case Bytecode::kReturn:
568 569 570 571 572 573 574 575 576 577 578 579 580 581
    case Bytecode::kSetPendingMessage:
      return true;
    default:
      if (FLAG_trace_side_effect_free_debug_evaluate) {
        PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
               Bytecodes::ToString(bytecode));
      }
      return false;
  }
}

bool BuiltinHasNoSideEffect(Builtins::Name id) {
  switch (id) {
    // Whitelist for builtins.
582
    // Object builtins.
583
    case Builtins::kObjectConstructor:
584 585 586 587 588 589 590 591 592 593 594
    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:
595
    case Builtins::kObjectPrototypeValueOf:
596
    case Builtins::kObjectValues:
597
    case Builtins::kObjectPrototypeHasOwnProperty:
598
    case Builtins::kObjectPrototypeIsPrototypeOf:
599
    case Builtins::kObjectPrototypePropertyIsEnumerable:
600
    case Builtins::kObjectPrototypeToString:
601
    // Array builtins.
602
    case Builtins::kArrayIsArray:
603
    case Builtins::kArrayConstructor:
604
    case Builtins::kArrayIndexOf:
605
    case Builtins::kArrayPrototypeValues:
606 607
    case Builtins::kArrayIncludes:
    case Builtins::kArrayPrototypeEntries:
608 609
    case Builtins::kArrayPrototypeFind:
    case Builtins::kArrayPrototypeFindIndex:
610
    case Builtins::kArrayPrototypeKeys:
611
    case Builtins::kArrayPrototypeSlice:
612
    case Builtins::kArrayForEach:
613 614
    case Builtins::kArrayEvery:
    case Builtins::kArraySome:
615 616 617 618
    case Builtins::kArrayConcat:
    case Builtins::kArraySlice:
    case Builtins::kArrayFilter:
    case Builtins::kArrayMap:
619
    case Builtins::kArrayReduce:
620
    case Builtins::kArrayReduceRight:
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
    // 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::kTypedArrayPrototypeIndexOf:
    case Builtins::kTypedArrayPrototypeLastIndexOf:
    case Builtins::kTypedArrayPrototypeSlice:
    case Builtins::kTypedArrayPrototypeSubArray:
    case Builtins::kTypedArrayPrototypeEvery:
    case Builtins::kTypedArrayPrototypeSome:
    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:
663 664
    case Builtins::kDataViewPrototypeGetBigInt64:
    case Builtins::kDataViewPrototypeGetBigUint64:
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
    // 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:
    case Builtins::kDatePrototypeToTimeString:
    case Builtins::kDatePrototypeToJson:
    case Builtins::kDatePrototypeToPrimitive:
    case Builtins::kDatePrototypeValueOf:
700 701
    // Map builtins.
    case Builtins::kMapConstructor:
702
    case Builtins::kMapPrototypeForEach:
703
    case Builtins::kMapPrototypeGet:
704
    case Builtins::kMapPrototypeHas:
705
    case Builtins::kMapPrototypeEntries:
706
    case Builtins::kMapPrototypeGetSize:
707 708
    case Builtins::kMapPrototypeKeys:
    case Builtins::kMapPrototypeValues:
709 710 711 712
    // WeakMap builtins.
    case Builtins::kWeakMapConstructor:
    case Builtins::kWeakMapGet:
    case Builtins::kWeakMapHas:
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    // 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:
743
    case Builtins::kMathSin:
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
    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::kNumberPrototypeValueOf:
762 763
    // Set builtins.
    case Builtins::kSetConstructor:
764
    case Builtins::kSetPrototypeEntries:
765
    case Builtins::kSetPrototypeForEach:
766
    case Builtins::kSetPrototypeGetSize:
767
    case Builtins::kSetPrototypeHas:
768
    case Builtins::kSetPrototypeValues:
769 770 771
    // WeakSet builtins.
    case Builtins::kWeakSetConstructor:
    case Builtins::kWeakSetHas:
772 773 774 775
    // String builtins. Strings are immutable.
    case Builtins::kStringFromCharCode:
    case Builtins::kStringFromCodePoint:
    case Builtins::kStringConstructor:
776 777 778 779
    case Builtins::kStringPrototypeAnchor:
    case Builtins::kStringPrototypeBig:
    case Builtins::kStringPrototypeBlink:
    case Builtins::kStringPrototypeBold:
780 781
    case Builtins::kStringPrototypeCharAt:
    case Builtins::kStringPrototypeCharCodeAt:
782
    case Builtins::kStringPrototypeCodePointAt:
783
    case Builtins::kStringPrototypeConcat:
784
    case Builtins::kStringPrototypeEndsWith:
785 786 787
    case Builtins::kStringPrototypeFixed:
    case Builtins::kStringPrototypeFontcolor:
    case Builtins::kStringPrototypeFontsize:
788 789
    case Builtins::kStringPrototypeIncludes:
    case Builtins::kStringPrototypeIndexOf:
790
    case Builtins::kStringPrototypeItalics:
791
    case Builtins::kStringPrototypeLastIndexOf:
792
    case Builtins::kStringPrototypeLink:
793 794
    case Builtins::kStringPrototypePadEnd:
    case Builtins::kStringPrototypePadStart:
795
    case Builtins::kStringPrototypeRepeat:
796
    case Builtins::kStringPrototypeSlice:
797
    case Builtins::kStringPrototypeSmall:
798
    case Builtins::kStringPrototypeStartsWith:
799 800
    case Builtins::kStringPrototypeStrike:
    case Builtins::kStringPrototypeSub:
801 802
    case Builtins::kStringPrototypeSubstr:
    case Builtins::kStringPrototypeSubstring:
803
    case Builtins::kStringPrototypeSup:
804
    case Builtins::kStringPrototypeToString:
805
#ifndef V8_INTL_SUPPORT
806 807
    case Builtins::kStringPrototypeToLowerCase:
    case Builtins::kStringPrototypeToUpperCase:
808
#endif
809
    case Builtins::kStringPrototypeTrim:
810 811
    case Builtins::kStringPrototypeTrimEnd:
    case Builtins::kStringPrototypeTrimStart:
812
    case Builtins::kStringPrototypeValueOf:
813
    case Builtins::kStringToNumber:
814
    case Builtins::kStringSubstring:
815 816 817 818 819 820
    // Symbol builtins.
    case Builtins::kSymbolConstructor:
    case Builtins::kSymbolKeyFor:
    case Builtins::kSymbolPrototypeToString:
    case Builtins::kSymbolPrototypeValueOf:
    case Builtins::kSymbolPrototypeToPrimitive:
821 822 823
    // JSON builtins.
    case Builtins::kJsonParse:
    case Builtins::kJsonStringify:
824 825 826 827 828 829 830
    // Global function builtins.
    case Builtins::kGlobalDecodeURI:
    case Builtins::kGlobalDecodeURIComponent:
    case Builtins::kGlobalEncodeURI:
    case Builtins::kGlobalEncodeURIComponent:
    case Builtins::kGlobalEscape:
    case Builtins::kGlobalUnescape:
831 832
    case Builtins::kGlobalIsFinite:
    case Builtins::kGlobalIsNaN:
833
    // Error builtins.
834
    case Builtins::kErrorConstructor:
835 836 837 838 839
    case Builtins::kMakeError:
    case Builtins::kMakeTypeError:
    case Builtins::kMakeSyntaxError:
    case Builtins::kMakeRangeError:
    case Builtins::kMakeURIError:
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
      return true;
    default:
      if (FLAG_trace_side_effect_free_debug_evaluate) {
        PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
               Builtins::name(id));
      }
      return false;
  }
}

}  // anonymous namespace

// static
bool DebugEvaluate::FunctionHasNoSideEffect(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->bytecode_array());
    if (FLAG_trace_side_effect_free_debug_evaluate) bytecode_array->Print();
    for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
         it.Advance()) {
      interpreter::Bytecode bytecode = it.current_bytecode();

      if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
870 871 872 873 874
        Runtime::FunctionId id =
            (bytecode == interpreter::Bytecode::kInvokeIntrinsic)
                ? it.GetIntrinsicIdOperand(0)
                : it.GetRuntimeIdOperand(0);
        if (IntrinsicHasNoSideEffect(id)) continue;
875 876 877 878 879 880 881 882 883 884 885
        return false;
      }

      if (BytecodeHasNoSideEffect(bytecode)) continue;

      // Did not match whitelist.
      return false;
    }
    return true;
  } else {
    // Check built-ins against whitelist.
886 887 888
    int builtin_index = info->HasLazyDeserializationBuiltinId()
                            ? info->lazy_deserialization_builtin_id()
                            : info->code()->builtin_index();
889
    DCHECK_NE(Builtins::kDeserializeLazy, builtin_index);
890
    if (Builtins::IsBuiltinId(builtin_index) &&
891
        BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) {
892
#ifdef DEBUG
893 894 895 896 897 898 899 900 901 902
      Isolate* isolate = info->GetIsolate();
      Code* code = isolate->builtins()->builtin(builtin_index);
      if (code->builtin_index() == Builtins::kDeserializeLazy) {
        // Target builtin is not yet deserialized. Deserialize it now.

        DCHECK(Builtins::IsLazy(builtin_index));
        DCHECK_EQ(Builtins::TFJ, Builtins::KindOf(builtin_index));

        code = Snapshot::DeserializeBuiltin(isolate, builtin_index);
        DCHECK_NE(Builtins::kDeserializeLazy, code->builtin_index());
903
      }
904
      // TODO(yangguo): Check builtin-to-builtin calls too.
905 906
      int mode = RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE);
      bool failed = false;
907
      for (RelocIterator it(code, mode); !it.done(); it.next()) {
908 909 910 911
        RelocInfo* rinfo = it.rinfo();
        Address address = rinfo->target_external_reference();
        const Runtime::Function* function = Runtime::FunctionForEntry(address);
        if (function == nullptr) continue;
912 913 914
        if (!BuiltinToIntrinsicHasNoSideEffect(
                static_cast<Builtins::Name>(builtin_index),
                function->function_id)) {
915 916 917 918
          PrintF("Whitelisted builtin %s calls non-whitelisted intrinsic %s\n",
                 Builtins::name(builtin_index), function->name);
          failed = true;
        }
919
        DCHECK(!failed);
920 921
      }
#endif  // DEBUG
922 923 924 925 926 927 928 929
      return true;
    }
  }

  return false;
}

// static
930 931 932 933 934 935 936 937 938 939 940
bool DebugEvaluate::CallbackHasNoSideEffect(Object* callback_info) {
  DisallowHeapAllocation no_gc;
  if (callback_info->IsAccessorInfo()) {
    // List of whitelisted internal accessors can be found in accessors.h.
    AccessorInfo* info = AccessorInfo::cast(callback_info);
    if (info->has_no_side_effect()) return true;
    if (FLAG_trace_side_effect_free_debug_evaluate) {
      PrintF("[debug-evaluate] API Callback '");
      info->name()->ShortPrint();
      PrintF("' may cause side effect.\n");
    }
941 942 943 944 945 946
  } else if (callback_info->IsInterceptorInfo()) {
    InterceptorInfo* info = InterceptorInfo::cast(callback_info);
    if (info->has_no_side_effect()) return true;
    if (FLAG_trace_side_effect_free_debug_evaluate) {
      PrintF("[debug-evaluate] API Interceptor may cause side effect.\n");
    }
947 948 949 950
  }
  return false;
}

951 952
}  // namespace internal
}  // namespace v8