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
IsDebugContext(Isolate * isolate,Context * context)22 static inline bool IsDebugContext(Isolate* isolate, Context* context) {
23 return context->native_context() == *isolate->debug()->debug_context();
24 }
25
Global(Isolate * isolate,Handle<String> source)26 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 SaveContext save(isolate);
33 SaveContext* top = &save;
34 while (top != NULL && IsDebugContext(isolate, *top->context())) {
35 top = top->prev();
36 }
37 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 Handle<Context> context = isolate->native_context();
42 Handle<JSObject> receiver(context->global_proxy());
43 Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
44 return Evaluate(isolate, outer_info, context, receiver, source, false);
45 }
46
Local(Isolate * isolate,StackFrame::Id frame_id,int inlined_jsframe_index,Handle<String> source,bool throw_on_side_effect)47 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 StackTraceFrameIterator it(isolate, frame_id);
57 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 DebugFrameHelper::FindSavedContextForFrame(isolate, frame);
64 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 ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
74 if (isolate->has_pending_exception()) return MaybeHandle<Object>();
75
76 Handle<Context> context = context_builder.evaluation_context();
77 Handle<JSObject> receiver(context->global_proxy());
78 MaybeHandle<Object> maybe_result =
79 Evaluate(isolate, context_builder.outer_info(), context, receiver, source,
80 throw_on_side_effect);
81 if (!maybe_result.is_null()) context_builder.UpdateValues();
82 return maybe_result;
83 }
84
85
86 // Compile and evaluate source for the given context.
Evaluate(Isolate * isolate,Handle<SharedFunctionInfo> outer_info,Handle<Context> context,Handle<Object> receiver,Handle<String> source,bool throw_on_side_effect)87 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 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 NoSideEffectScope no_side_effect(isolate, throw_on_side_effect);
102 ASSIGN_RETURN_ON_EXCEPTION(
103 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
104 Object);
105 }
106
107 // Skip the global proxy as it has no properties and always delegates to the
108 // real global object.
109 if (result->IsJSGlobalProxy()) {
110 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
ContextBuilder(Isolate * isolate,JavaScriptFrame * frame,int inlined_jsframe_index)119 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
120 JavaScriptFrame* frame,
121 int inlined_jsframe_index)
122 : isolate_(isolate),
123 frame_(frame),
124 inlined_jsframe_index_(inlined_jsframe_index) {
125 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
126 Handle<JSFunction> local_function = frame_inspector.GetFunction();
127 Handle<Context> outer_context(local_function->context());
128 evaluation_context_ = outer_context;
129 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 for (ScopeIterator it(isolate, &frame_inspector, option); !it.Done();
150 it.Next()) {
151 ScopeIterator::ScopeType scope_type = it.Type();
152 if (scope_type == ScopeIterator::ScopeTypeLocal) {
153 DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
154 Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
155 Handle<Context> local_context =
156 it.HasContext() ? it.CurrentContext() : outer_context;
157 Handle<StringSet> non_locals = it.GetNonLocals();
158 MaterializeReceiver(materialized, local_context, local_function,
159 non_locals);
160 frame_inspector.MaterializeStackLocals(materialized, local_function);
161 MaterializeArgumentsObject(materialized, local_function);
162 ContextChainElement context_chain_element;
163 context_chain_element.scope_info = it.CurrentScopeInfo();
164 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 context_chain_element.whitelist = non_locals;
168 if (it.HasContext()) {
169 context_chain_element.wrapped_context = it.CurrentContext();
170 }
171 context_chain_.Add(context_chain_element);
172 evaluation_context_ = outer_context;
173 break;
174 } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
175 scope_type == ScopeIterator::ScopeTypeWith) {
176 ContextChainElement context_chain_element;
177 Handle<Context> current_context = it.CurrentContext();
178 if (!current_context->IsDebugEvaluateContext()) {
179 context_chain_element.wrapped_context = current_context;
180 }
181 context_chain_.Add(context_chain_element);
182 } else if (scope_type == ScopeIterator::ScopeTypeBlock ||
183 scope_type == ScopeIterator::ScopeTypeEval) {
184 Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
185 frame_inspector.MaterializeStackLocals(materialized,
186 it.CurrentScopeInfo());
187 ContextChainElement context_chain_element;
188 context_chain_element.scope_info = it.CurrentScopeInfo();
189 context_chain_element.materialized_object = materialized;
190 if (it.HasContext()) {
191 context_chain_element.wrapped_context = it.CurrentContext();
192 }
193 context_chain_.Add(context_chain_element);
194 } else {
195 break;
196 }
197 }
198
199 for (int i = context_chain_.length() - 1; i >= 0; i--) {
200 Handle<ScopeInfo> scope_info(ScopeInfo::CreateForWithScope(
201 isolate, evaluation_context_->IsNativeContext()
202 ? Handle<ScopeInfo>::null()
203 : Handle<ScopeInfo>(evaluation_context_->scope_info())));
204 scope_info->SetIsDebugEvaluateScope();
205 evaluation_context_ = factory->NewDebugEvaluateContext(
206 evaluation_context_, scope_info, context_chain_[i].materialized_object,
207 context_chain_[i].wrapped_context, context_chain_[i].whitelist);
208 }
209 }
210
211
UpdateValues()212 void DebugEvaluate::ContextBuilder::UpdateValues() {
213 // TODO(yangguo): remove updating values.
214 for (int i = 0; i < context_chain_.length(); i++) {
215 ContextChainElement element = context_chain_[i];
216 if (!element.materialized_object.is_null()) {
217 // Write back potential changes to materialized stack locals to the stack.
218 FrameInspector(frame_, inlined_jsframe_index_, isolate_)
219 .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
220 element.scope_info);
221 }
222 }
223 }
224
225
MaterializeArgumentsObject(Handle<JSObject> target,Handle<JSFunction> function)226 void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject(
227 Handle<JSObject> target, Handle<JSFunction> function) {
228 // Do not materialize the arguments object for eval or top-level code.
229 // Skip if "arguments" is already taken.
230 if (function->shared()->is_toplevel()) return;
231 Maybe<bool> maybe = JSReceiver::HasOwnProperty(
232 target, isolate_->factory()->arguments_string());
233 DCHECK(maybe.IsJust());
234 if (maybe.FromJust()) return;
235
236 // FunctionGetArguments can't throw an exception.
237 Handle<JSObject> arguments = Accessors::FunctionGetArguments(function);
238 Handle<String> arguments_str = isolate_->factory()->arguments_string();
239 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
240 NONE)
241 .Check();
242 }
243
MaterializeReceiver(Handle<JSObject> target,Handle<Context> local_context,Handle<JSFunction> local_function,Handle<StringSet> non_locals)244 void DebugEvaluate::ContextBuilder::MaterializeReceiver(
245 Handle<JSObject> target, Handle<Context> local_context,
246 Handle<JSFunction> local_function, Handle<StringSet> non_locals) {
247 Handle<Object> recv = isolate_->factory()->undefined_value();
248 Handle<String> name = isolate_->factory()->this_string();
249 if (non_locals->Has(name)) {
250 // 'this' is allocated in an outer context and is is already being
251 // referenced by the current function, so it can be correctly resolved.
252 return;
253 } else if (local_function->shared()->scope_info()->HasReceiver() &&
254 !frame_->receiver()->IsTheHole(isolate_)) {
255 recv = handle(frame_->receiver(), isolate_);
256 }
257 JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
258 }
259
260 namespace {
261
IntrinsicHasNoSideEffect(Runtime::FunctionId id)262 bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
263 switch (id) {
264 // Whitelist for intrinsics amd runtime functions.
265 // Conversions.
266 case Runtime::kToInteger:
267 case Runtime::kInlineToInteger:
268 case Runtime::kToObject:
269 case Runtime::kInlineToObject:
270 case Runtime::kToString:
271 case Runtime::kInlineToString:
272 case Runtime::kToLength:
273 case Runtime::kInlineToLength:
274 case Runtime::kToNumber:
275 // Type checks.
276 case Runtime::kIsJSReceiver:
277 case Runtime::kInlineIsJSReceiver:
278 case Runtime::kIsSmi:
279 case Runtime::kInlineIsSmi:
280 case Runtime::kIsArray:
281 case Runtime::kInlineIsArray:
282 case Runtime::kIsFunction:
283 case Runtime::kIsDate:
284 case Runtime::kIsJSProxy:
285 case Runtime::kIsRegExp:
286 case Runtime::kIsTypedArray:
287 // Loads.
288 case Runtime::kLoadLookupSlotForCall:
289 // Arrays.
290 case Runtime::kArraySpeciesConstructor:
291 case Runtime::kNormalizeElements:
292 case Runtime::kGetArrayKeys:
293 case Runtime::kHasComplexElements:
294 case Runtime::kEstimateNumberOfElements:
295 // Errors.
296 case Runtime::kReThrow:
297 case Runtime::kThrowReferenceError:
298 case Runtime::kThrowSymbolIteratorInvalid:
299 case Runtime::kThrowIteratorResultNotAnObject:
300 case Runtime::kNewTypeError:
301 // Strings.
302 case Runtime::kInlineStringCharCodeAt:
303 case Runtime::kStringCharCodeAt:
304 case Runtime::kStringIndexOf:
305 case Runtime::kStringReplaceOneCharWithString:
306 case Runtime::kSubString:
307 case Runtime::kInlineSubString:
308 case Runtime::kRegExpInternalReplace:
309 // Literals.
310 case Runtime::kCreateArrayLiteral:
311 case Runtime::kCreateObjectLiteral:
312 case Runtime::kCreateRegExpLiteral:
313 // Misc.
314 case Runtime::kForInPrepare:
315 case Runtime::kInlineCall:
316 case Runtime::kCall:
317 case Runtime::kInlineMaxSmi:
318 case Runtime::kMaxSmi:
319 return true;
320 default:
321 if (FLAG_trace_side_effect_free_debug_evaluate) {
322 PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
323 Runtime::FunctionForId(id)->name);
324 }
325 return false;
326 }
327 }
328
BytecodeHasNoSideEffect(interpreter::Bytecode bytecode)329 bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
330 typedef interpreter::Bytecode Bytecode;
331 typedef interpreter::Bytecodes Bytecodes;
332 if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
333 if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
334 if (Bytecodes::WritesBooleanToAccumulator(bytecode)) return true;
335 if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
336 if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
337 switch (bytecode) {
338 // Whitelist for bytecodes.
339 // Loads.
340 case Bytecode::kLdaLookupSlot:
341 case Bytecode::kLdaGlobal:
342 case Bytecode::kLdaNamedProperty:
343 case Bytecode::kLdaKeyedProperty:
344 // Arithmetics.
345 case Bytecode::kAdd:
346 case Bytecode::kAddSmi:
347 case Bytecode::kSub:
348 case Bytecode::kSubSmi:
349 case Bytecode::kMul:
350 case Bytecode::kDiv:
351 case Bytecode::kMod:
352 case Bytecode::kBitwiseAnd:
353 case Bytecode::kBitwiseAndSmi:
354 case Bytecode::kBitwiseOr:
355 case Bytecode::kBitwiseOrSmi:
356 case Bytecode::kBitwiseXor:
357 case Bytecode::kShiftLeft:
358 case Bytecode::kShiftLeftSmi:
359 case Bytecode::kShiftRight:
360 case Bytecode::kShiftRightSmi:
361 case Bytecode::kShiftRightLogical:
362 case Bytecode::kInc:
363 case Bytecode::kDec:
364 case Bytecode::kLogicalNot:
365 case Bytecode::kToBooleanLogicalNot:
366 case Bytecode::kTypeOf:
367 // Contexts.
368 case Bytecode::kCreateBlockContext:
369 case Bytecode::kCreateCatchContext:
370 case Bytecode::kCreateFunctionContext:
371 case Bytecode::kCreateEvalContext:
372 case Bytecode::kCreateWithContext:
373 // Literals.
374 case Bytecode::kCreateArrayLiteral:
375 case Bytecode::kCreateObjectLiteral:
376 case Bytecode::kCreateRegExpLiteral:
377 // Allocations.
378 case Bytecode::kCreateClosure:
379 case Bytecode::kCreateUnmappedArguments:
380 // Conversions.
381 case Bytecode::kToObject:
382 case Bytecode::kToNumber:
383 // Misc.
384 case Bytecode::kForInPrepare:
385 case Bytecode::kForInContinue:
386 case Bytecode::kForInNext:
387 case Bytecode::kForInStep:
388 case Bytecode::kThrow:
389 case Bytecode::kReThrow:
390 case Bytecode::kIllegal:
391 case Bytecode::kCallJSRuntime:
392 case Bytecode::kStackCheck:
393 case Bytecode::kReturn:
394 case Bytecode::kSetPendingMessage:
395 return true;
396 default:
397 if (FLAG_trace_side_effect_free_debug_evaluate) {
398 PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
399 Bytecodes::ToString(bytecode));
400 }
401 return false;
402 }
403 }
404
BuiltinHasNoSideEffect(Builtins::Name id)405 bool BuiltinHasNoSideEffect(Builtins::Name id) {
406 switch (id) {
407 // Whitelist for builtins.
408 // Array builtins.
409 case Builtins::kArrayCode:
410 case Builtins::kArrayIndexOf:
411 case Builtins::kArrayPrototypeValues:
412 case Builtins::kArrayIncludes:
413 case Builtins::kArrayPrototypeEntries:
414 case Builtins::kArrayPrototypeKeys:
415 case Builtins::kArrayForEach:
416 // Math builtins.
417 case Builtins::kMathAbs:
418 case Builtins::kMathAcos:
419 case Builtins::kMathAcosh:
420 case Builtins::kMathAsin:
421 case Builtins::kMathAsinh:
422 case Builtins::kMathAtan:
423 case Builtins::kMathAtanh:
424 case Builtins::kMathAtan2:
425 case Builtins::kMathCeil:
426 case Builtins::kMathCbrt:
427 case Builtins::kMathExpm1:
428 case Builtins::kMathClz32:
429 case Builtins::kMathCos:
430 case Builtins::kMathCosh:
431 case Builtins::kMathExp:
432 case Builtins::kMathFloor:
433 case Builtins::kMathFround:
434 case Builtins::kMathHypot:
435 case Builtins::kMathImul:
436 case Builtins::kMathLog:
437 case Builtins::kMathLog1p:
438 case Builtins::kMathLog2:
439 case Builtins::kMathLog10:
440 case Builtins::kMathMax:
441 case Builtins::kMathMin:
442 case Builtins::kMathPow:
443 case Builtins::kMathRandom:
444 case Builtins::kMathRound:
445 case Builtins::kMathSign:
446 case Builtins::kMathSin:
447 case Builtins::kMathSinh:
448 case Builtins::kMathSqrt:
449 case Builtins::kMathTan:
450 case Builtins::kMathTanh:
451 case Builtins::kMathTrunc:
452 // Number builtins.
453 case Builtins::kNumberConstructor:
454 case Builtins::kNumberIsFinite:
455 case Builtins::kNumberIsInteger:
456 case Builtins::kNumberIsNaN:
457 case Builtins::kNumberIsSafeInteger:
458 case Builtins::kNumberParseFloat:
459 case Builtins::kNumberParseInt:
460 case Builtins::kNumberPrototypeToExponential:
461 case Builtins::kNumberPrototypeToFixed:
462 case Builtins::kNumberPrototypeToPrecision:
463 case Builtins::kNumberPrototypeToString:
464 case Builtins::kNumberPrototypeValueOf:
465 // String builtins. Strings are immutable.
466 case Builtins::kStringFromCharCode:
467 case Builtins::kStringFromCodePoint:
468 case Builtins::kStringConstructor:
469 case Builtins::kStringPrototypeCharAt:
470 case Builtins::kStringPrototypeCharCodeAt:
471 case Builtins::kStringPrototypeEndsWith:
472 case Builtins::kStringPrototypeIncludes:
473 case Builtins::kStringPrototypeIndexOf:
474 case Builtins::kStringPrototypeLastIndexOf:
475 case Builtins::kStringPrototypeStartsWith:
476 case Builtins::kStringPrototypeSubstr:
477 case Builtins::kStringPrototypeSubstring:
478 case Builtins::kStringPrototypeToString:
479 case Builtins::kStringPrototypeToLowerCase:
480 case Builtins::kStringPrototypeToUpperCase:
481 case Builtins::kStringPrototypeTrim:
482 case Builtins::kStringPrototypeTrimLeft:
483 case Builtins::kStringPrototypeTrimRight:
484 case Builtins::kStringPrototypeValueOf:
485 // JSON builtins.
486 case Builtins::kJsonParse:
487 case Builtins::kJsonStringify:
488 // Error builtins.
489 case Builtins::kMakeError:
490 case Builtins::kMakeTypeError:
491 case Builtins::kMakeSyntaxError:
492 case Builtins::kMakeRangeError:
493 case Builtins::kMakeURIError:
494 return true;
495 default:
496 if (FLAG_trace_side_effect_free_debug_evaluate) {
497 PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
498 Builtins::name(id));
499 }
500 return false;
501 }
502 }
503
504 static const Address accessors_with_no_side_effect[] = {
505 // Whitelist for accessors.
506 FUNCTION_ADDR(Accessors::StringLengthGetter),
507 FUNCTION_ADDR(Accessors::ArrayLengthGetter)};
508
509 } // anonymous namespace
510
511 // static
FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info)512 bool DebugEvaluate::FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info) {
513 if (FLAG_trace_side_effect_free_debug_evaluate) {
514 PrintF("[debug-evaluate] Checking function %s for side effect.\n",
515 info->DebugName()->ToCString().get());
516 }
517
518 DCHECK(info->is_compiled());
519
520 if (info->HasBytecodeArray()) {
521 // Check bytecodes against whitelist.
522 Handle<BytecodeArray> bytecode_array(info->bytecode_array());
523 if (FLAG_trace_side_effect_free_debug_evaluate) bytecode_array->Print();
524 for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
525 it.Advance()) {
526 interpreter::Bytecode bytecode = it.current_bytecode();
527
528 if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
529 Runtime::FunctionId id =
530 (bytecode == interpreter::Bytecode::kInvokeIntrinsic)
531 ? it.GetIntrinsicIdOperand(0)
532 : it.GetRuntimeIdOperand(0);
533 if (IntrinsicHasNoSideEffect(id)) continue;
534 return false;
535 }
536
537 if (BytecodeHasNoSideEffect(bytecode)) continue;
538
539 // Did not match whitelist.
540 return false;
541 }
542 return true;
543 } else {
544 // Check built-ins against whitelist.
545 int builtin_index = info->code()->builtin_index();
546 if (builtin_index >= 0 && builtin_index < Builtins::builtin_count &&
547 BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) {
548 return true;
549 }
550 }
551
552 return false;
553 }
554
555 // static
CallbackHasNoSideEffect(Address function_addr)556 bool DebugEvaluate::CallbackHasNoSideEffect(Address function_addr) {
557 for (size_t i = 0; i < arraysize(accessors_with_no_side_effect); i++) {
558 if (function_addr == accessors_with_no_side_effect[i]) return true;
559 }
560
561 if (FLAG_trace_side_effect_free_debug_evaluate) {
562 PrintF("[debug-evaluate] API Callback at %p may cause side effect.\n",
563 reinterpret_cast<void*>(function_addr));
564 }
565 return false;
566 }
567
568 } // namespace internal
569 } // namespace v8
570