Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: src/debug/debug-evaluate.cc

Issue 2622863003: [debugger] infrastructure for side-effect-free debug-evaluate. (Closed)
Patch Set: clean ups. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/debug/debug-evaluate.h" 5 #include "src/debug/debug-evaluate.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/compiler.h" 8 #include "src/compiler.h"
9 #include "src/contexts.h" 9 #include "src/contexts.h"
10 #include "src/debug/debug-frames.h" 10 #include "src/debug/debug-frames.h"
11 #include "src/debug/debug-scopes.h" 11 #include "src/debug/debug-scopes.h"
12 #include "src/debug/debug.h" 12 #include "src/debug/debug.h"
13 #include "src/frames-inl.h" 13 #include "src/frames-inl.h"
14 #include "src/globals.h" 14 #include "src/globals.h"
15 #include "src/interpreter/bytecode-array-iterator.h"
16 #include "src/interpreter/bytecodes.h"
15 #include "src/isolate-inl.h" 17 #include "src/isolate-inl.h"
16 18
17 namespace v8 { 19 namespace v8 {
18 namespace internal { 20 namespace internal {
19 21
20 static inline bool IsDebugContext(Isolate* isolate, Context* context) { 22 static inline bool IsDebugContext(Isolate* isolate, Context* context) {
21 return context->native_context() == *isolate->debug()->debug_context(); 23 return context->native_context() == *isolate->debug()->debug_context();
22 } 24 }
23 25
24 MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate, 26 MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 Handle<Context> context, Handle<Object> receiver, Handle<String> source) { 87 Handle<Context> context, Handle<Object> receiver, Handle<String> source) {
86 Handle<JSFunction> eval_fun; 88 Handle<JSFunction> eval_fun;
87 ASSIGN_RETURN_ON_EXCEPTION( 89 ASSIGN_RETURN_ON_EXCEPTION(
88 isolate, eval_fun, 90 isolate, eval_fun,
89 Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY, 91 Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
90 NO_PARSE_RESTRICTION, kNoSourcePosition, 92 NO_PARSE_RESTRICTION, kNoSourcePosition,
91 kNoSourcePosition), 93 kNoSourcePosition),
92 Object); 94 Object);
93 95
94 Handle<Object> result; 96 Handle<Object> result;
95 ASSIGN_RETURN_ON_EXCEPTION( 97 {
96 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL), 98 NoSideEffectScope no_side_effect(isolate,
97 Object); 99 FLAG_side_effect_free_debug_evaluate);
100 ASSIGN_RETURN_ON_EXCEPTION(
101 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
102 Object);
103 }
98 104
99 // Skip the global proxy as it has no properties and always delegates to the 105 // Skip the global proxy as it has no properties and always delegates to the
100 // real global object. 106 // real global object.
101 if (result->IsJSGlobalProxy()) { 107 if (result->IsJSGlobalProxy()) {
102 PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result)); 108 PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result));
103 // TODO(verwaest): This will crash when the global proxy is detached. 109 // TODO(verwaest): This will crash when the global proxy is detached.
104 result = PrototypeIterator::GetCurrent<JSObject>(iter); 110 result = PrototypeIterator::GetCurrent<JSObject>(iter);
105 } 111 }
106 112
107 return result; 113 return result;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 // 'this' is allocated in an outer context and is is already being 248 // 'this' is allocated in an outer context and is is already being
243 // referenced by the current function, so it can be correctly resolved. 249 // referenced by the current function, so it can be correctly resolved.
244 return; 250 return;
245 } else if (local_function->shared()->scope_info()->HasReceiver() && 251 } else if (local_function->shared()->scope_info()->HasReceiver() &&
246 !frame_->receiver()->IsTheHole(isolate_)) { 252 !frame_->receiver()->IsTheHole(isolate_)) {
247 recv = handle(frame_->receiver(), isolate_); 253 recv = handle(frame_->receiver(), isolate_);
248 } 254 }
249 JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check(); 255 JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
250 } 256 }
251 257
258 namespace {
jgruber 2017/01/11 16:12:39 Nit: whitespace.
259 bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
260 DCHECK_EQ(Runtime::INLINE, Runtime::FunctionForId(id)->intrinsic_type);
261 switch (id) {
262 // Whitelist for intrinsics.
263 case Runtime::kInlineToObject:
264 return true;
265 default:
266 if (FLAG_trace_side_effect_free_debug_evaluate) {
267 PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
268 Runtime::FunctionForId(id)->name);
269 }
270 return false;
271 }
272 }
273
274 bool RuntimeFunctionHasNoSideEffect(Runtime::FunctionId id) {
275 DCHECK_EQ(Runtime::RUNTIME, Runtime::FunctionForId(id)->intrinsic_type);
276 switch (id) {
277 // Whitelist for runtime functions.
278 case Runtime::kToObject:
279 case Runtime::kLoadLookupSlotForCall:
280 case Runtime::kThrowReferenceError:
281 return true;
282 default:
283 if (FLAG_trace_side_effect_free_debug_evaluate) {
284 PrintF("[debug-evaluate] runtime %s may cause side effect.\n",
285 Runtime::FunctionForId(id)->name);
286 }
287 return false;
288 }
289 }
290
291 bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
292 typedef interpreter::Bytecode Bytecode;
293 typedef interpreter::Bytecodes Bytecodes;
294 if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
295 if (Bytecodes::IsCallOrNew(bytecode)) return true;
296 switch (bytecode) {
297 // Whitelist for bytecodes.
298 case Bytecode::kStackCheck:
299 case Bytecode::kLdaLookupSlot:
300 case Bytecode::kLdaGlobal:
301 case Bytecode::kLdaNamedProperty:
302 case Bytecode::kLdaKeyedProperty:
303 case Bytecode::kAdd:
304 case Bytecode::kReturn:
305 case Bytecode::kCreateCatchContext:
306 case Bytecode::kSetPendingMessage:
307 return true;
308 default:
309 if (FLAG_trace_side_effect_free_debug_evaluate) {
310 PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
311 Bytecodes::ToString(bytecode));
312 }
313 return false;
314 }
315 }
316
317 bool BuiltinHasNoSideEffect(Builtins::Name id) {
318 switch (id) {
319 // Whitelist for builtins.
320 case Builtins::kMathSin:
321 return true;
322 default:
323 if (FLAG_trace_side_effect_free_debug_evaluate) {
324 PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
325 Builtins::name(id));
326 }
327 return false;
328 }
329 }
330
331 static const Address accessors_with_no_side_effect[] = {
332 // Whitelist for accessors.
333 FUNCTION_ADDR(Accessors::StringLengthGetter),
334 FUNCTION_ADDR(Accessors::ArrayLengthGetter)};
335
336 } // anonymous namespace
337
338 // static
339 bool DebugEvaluate::FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info) {
340 if (FLAG_trace_side_effect_free_debug_evaluate) {
341 PrintF("[debug-evaluate] Checking function %s for side effect.\n",
342 info->DebugName()->ToCString().get());
343 }
344
345 DCHECK(info->is_compiled());
346
347 if (info->HasBytecodeArray()) {
348 // Check bytecodes against whitelist.
349 Handle<BytecodeArray> bytecode_array(info->bytecode_array());
350 if (FLAG_trace_side_effect_free_debug_evaluate) bytecode_array->Print();
351 for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
352 it.Advance()) {
353 interpreter::Bytecode bytecode = it.current_bytecode();
354
355 if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
356 if (bytecode == interpreter::Bytecode::kInvokeIntrinsic &&
357 IntrinsicHasNoSideEffect(it.GetIntrinsicIdOperand(0))) {
358 continue;
359 } else if (RuntimeFunctionHasNoSideEffect(it.GetRuntimeIdOperand(0))) {
360 continue;
361 }
jgruber 2017/01/11 16:12:39 Maybe an explicit 'else return false' would be cle
Yang 2017/01/12 06:04:51 Done.
362 }
363
364 if (BytecodeHasNoSideEffect(bytecode)) continue;
365
366 // Did not match whitelist.
367 return false;
368 }
369 return true;
370 } else {
371 // Check built-ins against whitelist.
372 int builtin_index = info->code()->builtin_index();
373 if (builtin_index >= 0 && builtin_index < Builtins::builtin_count &&
374 BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) {
375 return true;
376 }
377 }
378
379 return false;
380 }
381
382 // static
383 bool DebugEvaluate::CallbackHasNoSideEffect(Address function_addr) {
384 for (size_t i = 0; i < arraysize(accessors_with_no_side_effect); i++) {
385 if (function_addr == accessors_with_no_side_effect[i]) return true;
386 }
387
388 if (FLAG_trace_side_effect_free_debug_evaluate) {
389 PrintF("[debug-evaluate] API Callback at %p may cause side effect.\n",
390 reinterpret_cast<void*>(function_addr));
391 }
392 return false;
393 }
394
252 } // namespace internal 395 } // namespace internal
253 } // namespace v8 396 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698