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/assembler-inl.h"
9 #include "src/compiler.h"
10 #include "src/contexts.h"
11 #include "src/debug/debug-frames.h"
12 #include "src/debug/debug-scopes.h"
13 #include "src/debug/debug.h"
14 #include "src/frames-inl.h"
15 #include "src/globals.h"
16 #include "src/interpreter/bytecode-array-iterator.h"
17 #include "src/interpreter/bytecodes.h"
18 #include "src/isolate-inl.h"
19 #include "src/objects/api-callbacks.h"
20 #include "src/snapshot/snapshot.h"
21
22 namespace v8 {
23 namespace internal {
24
Global(Isolate * isolate,Handle<String> source,bool throw_on_side_effect)25 MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
26 Handle<String> source,
27 bool throw_on_side_effect) {
28 // Disable breaks in side-effect free mode.
29 DisableBreak disable_break_scope(isolate->debug(), throw_on_side_effect);
30
31 Handle<Context> context = isolate->native_context();
32 ScriptOriginOptions origin_options(false, true);
33 MaybeHandle<SharedFunctionInfo> maybe_function_info =
34 Compiler::GetSharedFunctionInfoForScript(
35 isolate, source,
36 Compiler::ScriptDetails(isolate->factory()->empty_string()),
37 origin_options, nullptr, nullptr, ScriptCompiler::kNoCompileOptions,
38 ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE);
39
40 Handle<SharedFunctionInfo> shared_info;
41 if (!maybe_function_info.ToHandle(&shared_info)) return MaybeHandle<Object>();
42
43 Handle<JSFunction> fun =
44 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared_info,
45 context);
46 if (throw_on_side_effect) isolate->debug()->StartSideEffectCheckMode();
47 MaybeHandle<Object> result = Execution::Call(
48 isolate, fun, Handle<JSObject>(context->global_proxy(), isolate), 0,
49 nullptr);
50 if (throw_on_side_effect) isolate->debug()->StopSideEffectCheckMode();
51 return result;
52 }
53
Local(Isolate * isolate,StackFrame::Id frame_id,int inlined_jsframe_index,Handle<String> source,bool throw_on_side_effect)54 MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
55 StackFrame::Id frame_id,
56 int inlined_jsframe_index,
57 Handle<String> source,
58 bool throw_on_side_effect) {
59 // Handle the processing of break.
60 DisableBreak disable_break_scope(isolate->debug());
61
62 // Get the frame where the debugging is performed.
63 StackTraceFrameIterator it(isolate, frame_id);
64 if (!it.is_javascript()) return isolate->factory()->undefined_value();
65 JavaScriptFrame* frame = it.javascript_frame();
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(), isolate);
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
WithTopmostArguments(Isolate * isolate,Handle<String> source)85 MaybeHandle<Object> DebugEvaluate::WithTopmostArguments(Isolate* isolate,
86 Handle<String> source) {
87 // Handle the processing of break.
88 DisableBreak disable_break_scope(isolate->debug());
89 Factory* factory = isolate->factory();
90 JavaScriptFrameIterator it(isolate);
91
92 // Get context and receiver.
93 Handle<Context> native_context(
94 Context::cast(it.frame()->context())->native_context(), isolate);
95
96 // Materialize arguments as property on an extension object.
97 Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
98 Handle<String> arguments_str = factory->arguments_string();
99 JSObject::SetOwnPropertyIgnoreAttributes(
100 materialized, arguments_str,
101 Accessors::FunctionGetArguments(it.frame(), 0), NONE)
102 .Check();
103
104 // Materialize receiver.
105 Handle<String> this_str = factory->this_string();
106 JSObject::SetOwnPropertyIgnoreAttributes(
107 materialized, this_str, Handle<Object>(it.frame()->receiver(), isolate),
108 NONE)
109 .Check();
110
111 // Use extension object in a debug-evaluate scope.
112 Handle<ScopeInfo> scope_info =
113 ScopeInfo::CreateForWithScope(isolate, Handle<ScopeInfo>::null());
114 scope_info->SetIsDebugEvaluateScope();
115 Handle<Context> evaluation_context =
116 factory->NewDebugEvaluateContext(native_context, scope_info, materialized,
117 Handle<Context>(), Handle<StringSet>());
118 Handle<SharedFunctionInfo> outer_info(
119 native_context->empty_function()->shared(), isolate);
120 Handle<JSObject> receiver(native_context->global_proxy(), isolate);
121 const bool throw_on_side_effect = false;
122 MaybeHandle<Object> maybe_result =
123 Evaluate(isolate, outer_info, evaluation_context, receiver, source,
124 throw_on_side_effect);
125 return maybe_result;
126 }
127
128 // 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)129 MaybeHandle<Object> DebugEvaluate::Evaluate(
130 Isolate* isolate, Handle<SharedFunctionInfo> outer_info,
131 Handle<Context> context, Handle<Object> receiver, Handle<String> source,
132 bool throw_on_side_effect) {
133 Handle<JSFunction> eval_fun;
134 ASSIGN_RETURN_ON_EXCEPTION(
135 isolate, eval_fun,
136 Compiler::GetFunctionFromEval(source, outer_info, context,
137 LanguageMode::kSloppy, NO_PARSE_RESTRICTION,
138 kNoSourcePosition, kNoSourcePosition,
139 kNoSourcePosition),
140 Object);
141
142 Handle<Object> result;
143 bool sucess = false;
144 if (throw_on_side_effect) isolate->debug()->StartSideEffectCheckMode();
145 sucess = Execution::Call(isolate, eval_fun, receiver, 0, nullptr)
146 .ToHandle(&result);
147 if (throw_on_side_effect) isolate->debug()->StopSideEffectCheckMode();
148 if (!sucess) {
149 DCHECK(isolate->has_pending_exception());
150 return MaybeHandle<Object>();
151 }
152
153 // Skip the global proxy as it has no properties and always delegates to the
154 // real global object.
155 if (result->IsJSGlobalProxy()) {
156 PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result));
157 // TODO(verwaest): This will crash when the global proxy is detached.
158 result = PrototypeIterator::GetCurrent<JSObject>(iter);
159 }
160
161 return result;
162 }
163
outer_info() const164 Handle<SharedFunctionInfo> DebugEvaluate::ContextBuilder::outer_info() const {
165 return handle(frame_inspector_.GetFunction()->shared(), isolate_);
166 }
167
ContextBuilder(Isolate * isolate,JavaScriptFrame * frame,int inlined_jsframe_index)168 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
169 JavaScriptFrame* frame,
170 int inlined_jsframe_index)
171 : isolate_(isolate),
172 frame_inspector_(frame, inlined_jsframe_index, isolate),
173 scope_iterator_(isolate, &frame_inspector_,
174 ScopeIterator::COLLECT_NON_LOCALS) {
175 Handle<Context> outer_context(frame_inspector_.GetFunction()->context(),
176 isolate);
177 evaluation_context_ = outer_context;
178 Factory* factory = isolate->factory();
179
180 if (scope_iterator_.Done()) return;
181
182 // To evaluate as if we were running eval at the point of the debug break,
183 // we reconstruct the context chain as follows:
184 // - To make stack-allocated variables visible, we materialize them and
185 // use a debug-evaluate context to wrap both the materialized object and
186 // the original context.
187 // - We use the original context chain from the function context to the
188 // native context.
189 // - Between the function scope and the native context, we only resolve
190 // variable names that the current function already uses. Only for these
191 // names we can be sure that they will be correctly resolved. For the
192 // rest, we only resolve to with, script, and native contexts. We use a
193 // whitelist to implement that.
194 // Context::Lookup has special handling for debug-evaluate contexts:
195 // - Look up in the materialized stack variables.
196 // - Look up in the original context.
197 // - Check the whitelist to find out whether to skip contexts during lookup.
198 for (; scope_iterator_.InInnerScope(); scope_iterator_.Next()) {
199 ScopeIterator::ScopeType scope_type = scope_iterator_.Type();
200 if (scope_type == ScopeIterator::ScopeTypeScript) break;
201 ContextChainElement context_chain_element;
202 if (scope_type == ScopeIterator::ScopeTypeLocal ||
203 scope_iterator_.DeclaresLocals(ScopeIterator::Mode::STACK)) {
204 context_chain_element.materialized_object =
205 scope_iterator_.ScopeObject(ScopeIterator::Mode::STACK);
206 }
207 if (scope_iterator_.HasContext()) {
208 context_chain_element.wrapped_context = scope_iterator_.CurrentContext();
209 }
210 if (scope_type == ScopeIterator::ScopeTypeLocal) {
211 context_chain_element.whitelist = scope_iterator_.GetNonLocals();
212 }
213 context_chain_.push_back(context_chain_element);
214 }
215
216 Handle<ScopeInfo> scope_info =
217 evaluation_context_->IsNativeContext()
218 ? Handle<ScopeInfo>::null()
219 : handle(evaluation_context_->scope_info(), isolate);
220 for (auto rit = context_chain_.rbegin(); rit != context_chain_.rend();
221 rit++) {
222 ContextChainElement element = *rit;
223 scope_info = ScopeInfo::CreateForWithScope(isolate, scope_info);
224 scope_info->SetIsDebugEvaluateScope();
225 evaluation_context_ = factory->NewDebugEvaluateContext(
226 evaluation_context_, scope_info, element.materialized_object,
227 element.wrapped_context, element.whitelist);
228 }
229 }
230
231
UpdateValues()232 void DebugEvaluate::ContextBuilder::UpdateValues() {
233 scope_iterator_.Restart();
234 for (ContextChainElement& element : context_chain_) {
235 if (!element.materialized_object.is_null()) {
236 Handle<FixedArray> keys =
237 KeyAccumulator::GetKeys(element.materialized_object,
238 KeyCollectionMode::kOwnOnly,
239 ENUMERABLE_STRINGS)
240 .ToHandleChecked();
241
242 for (int i = 0; i < keys->length(); i++) {
243 DCHECK(keys->get(i)->IsString());
244 Handle<String> key(String::cast(keys->get(i)), isolate_);
245 Handle<Object> value =
246 JSReceiver::GetDataProperty(element.materialized_object, key);
247 scope_iterator_.SetVariableValue(key, value);
248 }
249 }
250 scope_iterator_.Next();
251 }
252 }
253
254 namespace {
255
IntrinsicHasNoSideEffect(Runtime::FunctionId id)256 bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
257 // Use macro to include both inlined and non-inlined version of an intrinsic.
258 #define INTRINSIC_WHITELIST(V) \
259 /* Conversions */ \
260 V(NumberToString) \
261 V(ToBigInt) \
262 V(ToInteger) \
263 V(ToLength) \
264 V(ToNumber) \
265 V(ToObject) \
266 V(ToString) \
267 /* Type checks */ \
268 V(IsArray) \
269 V(IsDate) \
270 V(IsFunction) \
271 V(IsJSProxy) \
272 V(IsJSReceiver) \
273 V(IsRegExp) \
274 V(IsSmi) \
275 V(IsTypedArray) \
276 /* Loads */ \
277 V(LoadLookupSlotForCall) \
278 V(GetProperty) \
279 /* Arrays */ \
280 V(ArraySpeciesConstructor) \
281 V(EstimateNumberOfElements) \
282 V(GetArrayKeys) \
283 V(HasComplexElements) \
284 V(HasFastPackedElements) \
285 V(NewArray) \
286 V(NormalizeElements) \
287 V(PrepareElementsForSort) \
288 V(TrySliceSimpleNonFastElements) \
289 V(TypedArrayGetBuffer) \
290 /* Errors */ \
291 V(NewTypeError) \
292 V(ReThrow) \
293 V(ThrowCalledNonCallable) \
294 V(ThrowInvalidStringLength) \
295 V(ThrowIteratorResultNotAnObject) \
296 V(ThrowReferenceError) \
297 V(ThrowSymbolIteratorInvalid) \
298 /* Strings */ \
299 V(RegExpInternalReplace) \
300 V(StringIncludes) \
301 V(StringIndexOf) \
302 V(StringReplaceOneCharWithString) \
303 V(StringSubstring) \
304 V(StringToNumber) \
305 V(StringTrim) \
306 /* BigInts */ \
307 V(BigIntEqualToBigInt) \
308 V(BigIntToBoolean) \
309 V(BigIntToNumber) \
310 /* Literals */ \
311 V(CreateArrayLiteral) \
312 V(CreateArrayLiteralWithoutAllocationSite) \
313 V(CreateObjectLiteral) \
314 V(CreateObjectLiteralWithoutAllocationSite) \
315 V(CreateRegExpLiteral) \
316 /* Called from builtins */ \
317 V(AllocateInNewSpace) \
318 V(AllocateInTargetSpace) \
319 V(AllocateSeqOneByteString) \
320 V(AllocateSeqTwoByteString) \
321 V(ArrayIncludes_Slow) \
322 V(ArrayIndexOf) \
323 V(ArrayIsArray) \
324 V(ClassOf) \
325 V(GenerateRandomNumbers) \
326 V(GetFunctionName) \
327 V(GetOwnPropertyDescriptor) \
328 V(GlobalPrint) \
329 V(HasProperty) \
330 V(ObjectCreate) \
331 V(ObjectEntries) \
332 V(ObjectEntriesSkipFastPath) \
333 V(ObjectHasOwnProperty) \
334 V(ObjectValues) \
335 V(ObjectValuesSkipFastPath) \
336 V(ObjectGetOwnPropertyNames) \
337 V(ObjectGetOwnPropertyNamesTryFast) \
338 V(RegExpInitializeAndCompile) \
339 V(StackGuard) \
340 V(StringAdd) \
341 V(StringCharCodeAt) \
342 V(StringEqual) \
343 V(StringIndexOfUnchecked) \
344 V(StringParseFloat) \
345 V(StringParseInt) \
346 V(SymbolDescriptiveString) \
347 V(ThrowRangeError) \
348 V(ThrowTypeError) \
349 V(ToName) \
350 V(TransitionElementsKind) \
351 /* Misc. */ \
352 V(Call) \
353 V(CompleteInobjectSlackTrackingForMap) \
354 V(HasInPrototypeChain) \
355 V(MaxSmi) \
356 V(NewObject) \
357 V(SmiLexicographicCompare) \
358 V(StringMaxLength) \
359 V(StringToArray) \
360 /* Test */ \
361 V(GetOptimizationStatus) \
362 V(OptimizeFunctionOnNextCall) \
363 V(OptimizeOsr) \
364 V(UnblockConcurrentRecompilation)
365
366 #define CASE(Name) \
367 case Runtime::k##Name: \
368 case Runtime::kInline##Name:
369
370 switch (id) {
371 INTRINSIC_WHITELIST(CASE)
372 return true;
373 default:
374 if (FLAG_trace_side_effect_free_debug_evaluate) {
375 PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
376 Runtime::FunctionForId(id)->name);
377 }
378 return false;
379 }
380
381 #undef CASE
382 #undef INTRINSIC_WHITELIST
383 }
384
385 #ifdef DEBUG
BuiltinToIntrinsicHasNoSideEffect(Builtins::Name builtin_id,Runtime::FunctionId intrinsic_id)386 bool BuiltinToIntrinsicHasNoSideEffect(Builtins::Name builtin_id,
387 Runtime::FunctionId intrinsic_id) {
388 // First check the intrinsic whitelist.
389 if (IntrinsicHasNoSideEffect(intrinsic_id)) return true;
390
391 // Whitelist intrinsics called from specific builtins.
392 #define BUILTIN_INTRINSIC_WHITELIST(V, W) \
393 /* Arrays */ \
394 V(Builtins::kArrayFilter, W(CreateDataProperty)) \
395 V(Builtins::kArrayMap, W(CreateDataProperty)) \
396 V(Builtins::kArrayPrototypeSlice, W(CreateDataProperty) W(SetProperty)) \
397 /* TypedArrays */ \
398 V(Builtins::kTypedArrayConstructor, \
399 W(TypedArrayCopyElements) W(ThrowInvalidTypedArrayAlignment)) \
400 V(Builtins::kTypedArrayPrototypeFilter, W(TypedArrayCopyElements)) \
401 V(Builtins::kTypedArrayPrototypeMap, W(SetProperty))
402
403 #define CASE(Builtin, ...) \
404 case Builtin: \
405 return (__VA_ARGS__ false);
406
407 #define MATCH(Intrinsic) \
408 intrinsic_id == Runtime::k##Intrinsic || \
409 intrinsic_id == Runtime::kInline##Intrinsic ||
410
411 switch (builtin_id) {
412 BUILTIN_INTRINSIC_WHITELIST(CASE, MATCH)
413 default:
414 return false;
415 }
416
417 #undef MATCH
418 #undef CASE
419 #undef BUILTIN_INTRINSIC_WHITELIST
420 }
421 #endif // DEBUG
422
BytecodeHasNoSideEffect(interpreter::Bytecode bytecode)423 bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
424 typedef interpreter::Bytecode Bytecode;
425 typedef interpreter::Bytecodes Bytecodes;
426 if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
427 if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
428 if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
429 if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
430 switch (bytecode) {
431 // Whitelist for bytecodes.
432 // Loads.
433 case Bytecode::kLdaLookupSlot:
434 case Bytecode::kLdaGlobal:
435 case Bytecode::kLdaNamedProperty:
436 case Bytecode::kLdaKeyedProperty:
437 case Bytecode::kLdaGlobalInsideTypeof:
438 case Bytecode::kLdaLookupSlotInsideTypeof:
439 // Arithmetics.
440 case Bytecode::kAdd:
441 case Bytecode::kAddSmi:
442 case Bytecode::kSub:
443 case Bytecode::kSubSmi:
444 case Bytecode::kMul:
445 case Bytecode::kMulSmi:
446 case Bytecode::kDiv:
447 case Bytecode::kDivSmi:
448 case Bytecode::kMod:
449 case Bytecode::kModSmi:
450 case Bytecode::kExp:
451 case Bytecode::kExpSmi:
452 case Bytecode::kNegate:
453 case Bytecode::kBitwiseAnd:
454 case Bytecode::kBitwiseAndSmi:
455 case Bytecode::kBitwiseNot:
456 case Bytecode::kBitwiseOr:
457 case Bytecode::kBitwiseOrSmi:
458 case Bytecode::kBitwiseXor:
459 case Bytecode::kBitwiseXorSmi:
460 case Bytecode::kShiftLeft:
461 case Bytecode::kShiftLeftSmi:
462 case Bytecode::kShiftRight:
463 case Bytecode::kShiftRightSmi:
464 case Bytecode::kShiftRightLogical:
465 case Bytecode::kShiftRightLogicalSmi:
466 case Bytecode::kInc:
467 case Bytecode::kDec:
468 case Bytecode::kLogicalNot:
469 case Bytecode::kToBooleanLogicalNot:
470 case Bytecode::kTypeOf:
471 // Contexts.
472 case Bytecode::kCreateBlockContext:
473 case Bytecode::kCreateCatchContext:
474 case Bytecode::kCreateFunctionContext:
475 case Bytecode::kCreateEvalContext:
476 case Bytecode::kCreateWithContext:
477 // Literals.
478 case Bytecode::kCreateArrayLiteral:
479 case Bytecode::kCreateEmptyArrayLiteral:
480 case Bytecode::kCreateObjectLiteral:
481 case Bytecode::kCreateEmptyObjectLiteral:
482 case Bytecode::kCreateRegExpLiteral:
483 // Allocations.
484 case Bytecode::kCreateClosure:
485 case Bytecode::kCreateUnmappedArguments:
486 case Bytecode::kCreateRestParameter:
487 // Comparisons.
488 case Bytecode::kTestEqual:
489 case Bytecode::kTestEqualStrict:
490 case Bytecode::kTestLessThan:
491 case Bytecode::kTestLessThanOrEqual:
492 case Bytecode::kTestGreaterThan:
493 case Bytecode::kTestGreaterThanOrEqual:
494 case Bytecode::kTestInstanceOf:
495 case Bytecode::kTestIn:
496 case Bytecode::kTestReferenceEqual:
497 case Bytecode::kTestUndetectable:
498 case Bytecode::kTestTypeOf:
499 case Bytecode::kTestUndefined:
500 case Bytecode::kTestNull:
501 // Conversions.
502 case Bytecode::kToObject:
503 case Bytecode::kToName:
504 case Bytecode::kToNumber:
505 case Bytecode::kToNumeric:
506 case Bytecode::kToString:
507 // Misc.
508 case Bytecode::kForInEnumerate:
509 case Bytecode::kForInPrepare:
510 case Bytecode::kForInContinue:
511 case Bytecode::kForInNext:
512 case Bytecode::kForInStep:
513 case Bytecode::kThrow:
514 case Bytecode::kReThrow:
515 case Bytecode::kThrowReferenceErrorIfHole:
516 case Bytecode::kThrowSuperNotCalledIfHole:
517 case Bytecode::kThrowSuperAlreadyCalledIfNotHole:
518 case Bytecode::kIllegal:
519 case Bytecode::kCallJSRuntime:
520 case Bytecode::kStackCheck:
521 case Bytecode::kReturn:
522 case Bytecode::kSetPendingMessage:
523 return true;
524 default:
525 return false;
526 }
527 }
528
BuiltinGetSideEffectState(Builtins::Name id)529 DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtins::Name id) {
530 switch (id) {
531 // Whitelist for builtins.
532 // Object builtins.
533 case Builtins::kObjectConstructor:
534 case Builtins::kObjectCreate:
535 case Builtins::kObjectEntries:
536 case Builtins::kObjectGetOwnPropertyDescriptor:
537 case Builtins::kObjectGetOwnPropertyDescriptors:
538 case Builtins::kObjectGetOwnPropertyNames:
539 case Builtins::kObjectGetOwnPropertySymbols:
540 case Builtins::kObjectGetPrototypeOf:
541 case Builtins::kObjectIs:
542 case Builtins::kObjectIsExtensible:
543 case Builtins::kObjectIsFrozen:
544 case Builtins::kObjectIsSealed:
545 case Builtins::kObjectPrototypeValueOf:
546 case Builtins::kObjectValues:
547 case Builtins::kObjectPrototypeHasOwnProperty:
548 case Builtins::kObjectPrototypeIsPrototypeOf:
549 case Builtins::kObjectPrototypePropertyIsEnumerable:
550 case Builtins::kObjectPrototypeToString:
551 // Array builtins.
552 case Builtins::kArrayIsArray:
553 case Builtins::kArrayConstructor:
554 case Builtins::kArrayIndexOf:
555 case Builtins::kArrayPrototypeValues:
556 case Builtins::kArrayIncludes:
557 case Builtins::kArrayPrototypeEntries:
558 case Builtins::kArrayPrototypeFill:
559 case Builtins::kArrayPrototypeFind:
560 case Builtins::kArrayPrototypeFindIndex:
561 case Builtins::kArrayPrototypeFlat:
562 case Builtins::kArrayPrototypeFlatMap:
563 case Builtins::kArrayPrototypeKeys:
564 case Builtins::kArrayPrototypeSlice:
565 case Builtins::kArrayPrototypeSort:
566 case Builtins::kArrayForEach:
567 case Builtins::kArrayEvery:
568 case Builtins::kArraySome:
569 case Builtins::kArrayConcat:
570 case Builtins::kArrayFilter:
571 case Builtins::kArrayMap:
572 case Builtins::kArrayReduce:
573 case Builtins::kArrayReduceRight:
574 // Trace builtins.
575 case Builtins::kIsTraceCategoryEnabled:
576 case Builtins::kTrace:
577 // TypedArray builtins.
578 case Builtins::kTypedArrayConstructor:
579 case Builtins::kTypedArrayPrototypeBuffer:
580 case Builtins::kTypedArrayPrototypeByteLength:
581 case Builtins::kTypedArrayPrototypeByteOffset:
582 case Builtins::kTypedArrayPrototypeLength:
583 case Builtins::kTypedArrayPrototypeEntries:
584 case Builtins::kTypedArrayPrototypeKeys:
585 case Builtins::kTypedArrayPrototypeValues:
586 case Builtins::kTypedArrayPrototypeFind:
587 case Builtins::kTypedArrayPrototypeFindIndex:
588 case Builtins::kTypedArrayPrototypeIncludes:
589 case Builtins::kTypedArrayPrototypeIndexOf:
590 case Builtins::kTypedArrayPrototypeLastIndexOf:
591 case Builtins::kTypedArrayPrototypeSlice:
592 case Builtins::kTypedArrayPrototypeSubArray:
593 case Builtins::kTypedArrayPrototypeEvery:
594 case Builtins::kTypedArrayPrototypeSome:
595 case Builtins::kTypedArrayPrototypeFilter:
596 case Builtins::kTypedArrayPrototypeMap:
597 case Builtins::kTypedArrayPrototypeReduce:
598 case Builtins::kTypedArrayPrototypeReduceRight:
599 case Builtins::kTypedArrayPrototypeForEach:
600 // ArrayBuffer builtins.
601 case Builtins::kArrayBufferConstructor:
602 case Builtins::kArrayBufferPrototypeGetByteLength:
603 case Builtins::kArrayBufferIsView:
604 case Builtins::kArrayBufferPrototypeSlice:
605 case Builtins::kReturnReceiver:
606 // DataView builtins.
607 case Builtins::kDataViewConstructor:
608 case Builtins::kDataViewPrototypeGetBuffer:
609 case Builtins::kDataViewPrototypeGetByteLength:
610 case Builtins::kDataViewPrototypeGetByteOffset:
611 case Builtins::kDataViewPrototypeGetInt8:
612 case Builtins::kDataViewPrototypeGetUint8:
613 case Builtins::kDataViewPrototypeGetInt16:
614 case Builtins::kDataViewPrototypeGetUint16:
615 case Builtins::kDataViewPrototypeGetInt32:
616 case Builtins::kDataViewPrototypeGetUint32:
617 case Builtins::kDataViewPrototypeGetFloat32:
618 case Builtins::kDataViewPrototypeGetFloat64:
619 case Builtins::kDataViewPrototypeGetBigInt64:
620 case Builtins::kDataViewPrototypeGetBigUint64:
621 // Boolean bulitins.
622 case Builtins::kBooleanConstructor:
623 case Builtins::kBooleanPrototypeToString:
624 case Builtins::kBooleanPrototypeValueOf:
625 // Date builtins.
626 case Builtins::kDateConstructor:
627 case Builtins::kDateNow:
628 case Builtins::kDateParse:
629 case Builtins::kDatePrototypeGetDate:
630 case Builtins::kDatePrototypeGetDay:
631 case Builtins::kDatePrototypeGetFullYear:
632 case Builtins::kDatePrototypeGetHours:
633 case Builtins::kDatePrototypeGetMilliseconds:
634 case Builtins::kDatePrototypeGetMinutes:
635 case Builtins::kDatePrototypeGetMonth:
636 case Builtins::kDatePrototypeGetSeconds:
637 case Builtins::kDatePrototypeGetTime:
638 case Builtins::kDatePrototypeGetTimezoneOffset:
639 case Builtins::kDatePrototypeGetUTCDate:
640 case Builtins::kDatePrototypeGetUTCDay:
641 case Builtins::kDatePrototypeGetUTCFullYear:
642 case Builtins::kDatePrototypeGetUTCHours:
643 case Builtins::kDatePrototypeGetUTCMilliseconds:
644 case Builtins::kDatePrototypeGetUTCMinutes:
645 case Builtins::kDatePrototypeGetUTCMonth:
646 case Builtins::kDatePrototypeGetUTCSeconds:
647 case Builtins::kDatePrototypeGetYear:
648 case Builtins::kDatePrototypeToDateString:
649 case Builtins::kDatePrototypeToISOString:
650 case Builtins::kDatePrototypeToUTCString:
651 case Builtins::kDatePrototypeToString:
652 case Builtins::kDatePrototypeToTimeString:
653 case Builtins::kDatePrototypeToJson:
654 case Builtins::kDatePrototypeToPrimitive:
655 case Builtins::kDatePrototypeValueOf:
656 // Map builtins.
657 case Builtins::kMapConstructor:
658 case Builtins::kMapPrototypeForEach:
659 case Builtins::kMapPrototypeGet:
660 case Builtins::kMapPrototypeHas:
661 case Builtins::kMapPrototypeEntries:
662 case Builtins::kMapPrototypeGetSize:
663 case Builtins::kMapPrototypeKeys:
664 case Builtins::kMapPrototypeValues:
665 // WeakMap builtins.
666 case Builtins::kWeakMapConstructor:
667 case Builtins::kWeakMapGet:
668 case Builtins::kWeakMapHas:
669 // Math builtins.
670 case Builtins::kMathAbs:
671 case Builtins::kMathAcos:
672 case Builtins::kMathAcosh:
673 case Builtins::kMathAsin:
674 case Builtins::kMathAsinh:
675 case Builtins::kMathAtan:
676 case Builtins::kMathAtanh:
677 case Builtins::kMathAtan2:
678 case Builtins::kMathCeil:
679 case Builtins::kMathCbrt:
680 case Builtins::kMathExpm1:
681 case Builtins::kMathClz32:
682 case Builtins::kMathCos:
683 case Builtins::kMathCosh:
684 case Builtins::kMathExp:
685 case Builtins::kMathFloor:
686 case Builtins::kMathFround:
687 case Builtins::kMathHypot:
688 case Builtins::kMathImul:
689 case Builtins::kMathLog:
690 case Builtins::kMathLog1p:
691 case Builtins::kMathLog2:
692 case Builtins::kMathLog10:
693 case Builtins::kMathMax:
694 case Builtins::kMathMin:
695 case Builtins::kMathPow:
696 case Builtins::kMathRandom:
697 case Builtins::kMathRound:
698 case Builtins::kMathSign:
699 case Builtins::kMathSin:
700 case Builtins::kMathSinh:
701 case Builtins::kMathSqrt:
702 case Builtins::kMathTan:
703 case Builtins::kMathTanh:
704 case Builtins::kMathTrunc:
705 // Number builtins.
706 case Builtins::kNumberConstructor:
707 case Builtins::kNumberIsFinite:
708 case Builtins::kNumberIsInteger:
709 case Builtins::kNumberIsNaN:
710 case Builtins::kNumberIsSafeInteger:
711 case Builtins::kNumberParseFloat:
712 case Builtins::kNumberParseInt:
713 case Builtins::kNumberPrototypeToExponential:
714 case Builtins::kNumberPrototypeToFixed:
715 case Builtins::kNumberPrototypeToPrecision:
716 case Builtins::kNumberPrototypeToString:
717 case Builtins::kNumberPrototypeValueOf:
718 // BigInt builtins.
719 case Builtins::kBigIntConstructor:
720 case Builtins::kBigIntAsIntN:
721 case Builtins::kBigIntAsUintN:
722 case Builtins::kBigIntPrototypeToString:
723 case Builtins::kBigIntPrototypeValueOf:
724 // Set builtins.
725 case Builtins::kSetConstructor:
726 case Builtins::kSetPrototypeEntries:
727 case Builtins::kSetPrototypeForEach:
728 case Builtins::kSetPrototypeGetSize:
729 case Builtins::kSetPrototypeHas:
730 case Builtins::kSetPrototypeValues:
731 // WeakSet builtins.
732 case Builtins::kWeakSetConstructor:
733 case Builtins::kWeakSetHas:
734 // String builtins. Strings are immutable.
735 case Builtins::kStringFromCharCode:
736 case Builtins::kStringFromCodePoint:
737 case Builtins::kStringConstructor:
738 case Builtins::kStringPrototypeAnchor:
739 case Builtins::kStringPrototypeBig:
740 case Builtins::kStringPrototypeBlink:
741 case Builtins::kStringPrototypeBold:
742 case Builtins::kStringPrototypeCharAt:
743 case Builtins::kStringPrototypeCharCodeAt:
744 case Builtins::kStringPrototypeCodePointAt:
745 case Builtins::kStringPrototypeConcat:
746 case Builtins::kStringPrototypeEndsWith:
747 case Builtins::kStringPrototypeFixed:
748 case Builtins::kStringPrototypeFontcolor:
749 case Builtins::kStringPrototypeFontsize:
750 case Builtins::kStringPrototypeIncludes:
751 case Builtins::kStringPrototypeIndexOf:
752 case Builtins::kStringPrototypeItalics:
753 case Builtins::kStringPrototypeLastIndexOf:
754 case Builtins::kStringPrototypeLink:
755 case Builtins::kStringPrototypePadEnd:
756 case Builtins::kStringPrototypePadStart:
757 case Builtins::kStringPrototypeRepeat:
758 case Builtins::kStringPrototypeSlice:
759 case Builtins::kStringPrototypeSmall:
760 case Builtins::kStringPrototypeStartsWith:
761 case Builtins::kStringPrototypeStrike:
762 case Builtins::kStringPrototypeSub:
763 case Builtins::kStringPrototypeSubstr:
764 case Builtins::kStringPrototypeSubstring:
765 case Builtins::kStringPrototypeSup:
766 case Builtins::kStringPrototypeToString:
767 #ifndef V8_INTL_SUPPORT
768 case Builtins::kStringPrototypeToLowerCase:
769 case Builtins::kStringPrototypeToUpperCase:
770 #endif
771 case Builtins::kStringPrototypeTrim:
772 case Builtins::kStringPrototypeTrimEnd:
773 case Builtins::kStringPrototypeTrimStart:
774 case Builtins::kStringPrototypeValueOf:
775 case Builtins::kStringToNumber:
776 case Builtins::kStringSubstring:
777 // Symbol builtins.
778 case Builtins::kSymbolConstructor:
779 case Builtins::kSymbolKeyFor:
780 case Builtins::kSymbolPrototypeToString:
781 case Builtins::kSymbolPrototypeValueOf:
782 case Builtins::kSymbolPrototypeToPrimitive:
783 // JSON builtins.
784 case Builtins::kJsonParse:
785 case Builtins::kJsonStringify:
786 // Global function builtins.
787 case Builtins::kGlobalDecodeURI:
788 case Builtins::kGlobalDecodeURIComponent:
789 case Builtins::kGlobalEncodeURI:
790 case Builtins::kGlobalEncodeURIComponent:
791 case Builtins::kGlobalEscape:
792 case Builtins::kGlobalUnescape:
793 case Builtins::kGlobalIsFinite:
794 case Builtins::kGlobalIsNaN:
795 // Function builtins.
796 case Builtins::kFunctionPrototypeToString:
797 case Builtins::kFunctionPrototypeBind:
798 case Builtins::kFastFunctionPrototypeBind:
799 case Builtins::kFunctionPrototypeCall:
800 case Builtins::kFunctionPrototypeApply:
801 // Error builtins.
802 case Builtins::kErrorConstructor:
803 case Builtins::kMakeError:
804 case Builtins::kMakeTypeError:
805 case Builtins::kMakeSyntaxError:
806 case Builtins::kMakeRangeError:
807 case Builtins::kMakeURIError:
808 // RegExp builtins.
809 case Builtins::kRegExpConstructor:
810 return DebugInfo::kHasNoSideEffect;
811 // Set builtins.
812 case Builtins::kSetIteratorPrototypeNext:
813 case Builtins::kSetPrototypeAdd:
814 case Builtins::kSetPrototypeClear:
815 case Builtins::kSetPrototypeDelete:
816 // Array builtins.
817 case Builtins::kArrayIteratorPrototypeNext:
818 case Builtins::kArrayPrototypePop:
819 case Builtins::kArrayPrototypePush:
820 case Builtins::kArrayPrototypeReverse:
821 case Builtins::kArrayPrototypeShift:
822 case Builtins::kArraySplice:
823 case Builtins::kArrayUnshift:
824 // Map builtins.
825 case Builtins::kMapIteratorPrototypeNext:
826 case Builtins::kMapPrototypeClear:
827 case Builtins::kMapPrototypeDelete:
828 case Builtins::kMapPrototypeSet:
829 // RegExp builtins.
830 case Builtins::kRegExpPrototypeTest:
831 case Builtins::kRegExpPrototypeExec:
832 case Builtins::kRegExpPrototypeSplit:
833 case Builtins::kRegExpPrototypeFlagsGetter:
834 case Builtins::kRegExpPrototypeGlobalGetter:
835 case Builtins::kRegExpPrototypeIgnoreCaseGetter:
836 case Builtins::kRegExpPrototypeMultilineGetter:
837 case Builtins::kRegExpPrototypeDotAllGetter:
838 case Builtins::kRegExpPrototypeUnicodeGetter:
839 case Builtins::kRegExpPrototypeStickyGetter:
840 return DebugInfo::kRequiresRuntimeChecks;
841 default:
842 if (FLAG_trace_side_effect_free_debug_evaluate) {
843 PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
844 Builtins::name(id));
845 }
846 return DebugInfo::kHasSideEffects;
847 }
848 }
849
BytecodeRequiresRuntimeCheck(interpreter::Bytecode bytecode)850 bool BytecodeRequiresRuntimeCheck(interpreter::Bytecode bytecode) {
851 typedef interpreter::Bytecode Bytecode;
852 switch (bytecode) {
853 case Bytecode::kStaNamedProperty:
854 case Bytecode::kStaNamedOwnProperty:
855 case Bytecode::kStaKeyedProperty:
856 case Bytecode::kStaInArrayLiteral:
857 case Bytecode::kStaDataPropertyInLiteral:
858 case Bytecode::kStaCurrentContextSlot:
859 return true;
860 default:
861 return false;
862 }
863 }
864
865 } // anonymous namespace
866
867 // static
FunctionGetSideEffectState(Isolate * isolate,Handle<SharedFunctionInfo> info)868 DebugInfo::SideEffectState DebugEvaluate::FunctionGetSideEffectState(
869 Isolate* isolate, Handle<SharedFunctionInfo> info) {
870 if (FLAG_trace_side_effect_free_debug_evaluate) {
871 PrintF("[debug-evaluate] Checking function %s for side effect.\n",
872 info->DebugName()->ToCString().get());
873 }
874
875 DCHECK(info->is_compiled());
876 if (info->HasBytecodeArray()) {
877 // Check bytecodes against whitelist.
878 Handle<BytecodeArray> bytecode_array(info->GetBytecodeArray(), isolate);
879 if (FLAG_trace_side_effect_free_debug_evaluate) {
880 bytecode_array->Print();
881 }
882 bool requires_runtime_checks = false;
883 for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
884 it.Advance()) {
885 interpreter::Bytecode bytecode = it.current_bytecode();
886
887 if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
888 Runtime::FunctionId id =
889 (bytecode == interpreter::Bytecode::kInvokeIntrinsic)
890 ? it.GetIntrinsicIdOperand(0)
891 : it.GetRuntimeIdOperand(0);
892 if (IntrinsicHasNoSideEffect(id)) continue;
893 return DebugInfo::kHasSideEffects;
894 }
895
896 if (BytecodeHasNoSideEffect(bytecode)) continue;
897 if (BytecodeRequiresRuntimeCheck(bytecode)) {
898 requires_runtime_checks = true;
899 continue;
900 }
901
902 if (FLAG_trace_side_effect_free_debug_evaluate) {
903 PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
904 interpreter::Bytecodes::ToString(bytecode));
905 }
906
907 // Did not match whitelist.
908 return DebugInfo::kHasSideEffects;
909 }
910 return requires_runtime_checks ? DebugInfo::kRequiresRuntimeChecks
911 : DebugInfo::kHasNoSideEffect;
912 } else if (info->IsApiFunction()) {
913 if (info->GetCode()->is_builtin()) {
914 return info->GetCode()->builtin_index() == Builtins::kHandleApiCall
915 ? DebugInfo::kHasNoSideEffect
916 : DebugInfo::kHasSideEffects;
917 }
918 } else {
919 // Check built-ins against whitelist.
920 int builtin_index =
921 info->HasBuiltinId() ? info->builtin_id() : Builtins::kNoBuiltinId;
922 DCHECK_NE(Builtins::kDeserializeLazy, builtin_index);
923 if (!Builtins::IsBuiltinId(builtin_index))
924 return DebugInfo::kHasSideEffects;
925 DebugInfo::SideEffectState state =
926 BuiltinGetSideEffectState(static_cast<Builtins::Name>(builtin_index));
927 #ifdef DEBUG
928 if (state == DebugInfo::kHasNoSideEffect) {
929 Code* code = isolate->builtins()->builtin(builtin_index);
930 if (code->builtin_index() == Builtins::kDeserializeLazy) {
931 // Target builtin is not yet deserialized. Deserialize it now.
932
933 DCHECK(Builtins::IsLazy(builtin_index));
934 DCHECK_EQ(Builtins::TFJ, Builtins::KindOf(builtin_index));
935
936 code = Snapshot::DeserializeBuiltin(isolate, builtin_index);
937 DCHECK_NE(Builtins::kDeserializeLazy, code->builtin_index());
938 }
939 // TODO(yangguo): Check builtin-to-builtin calls too.
940 int mode = RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE);
941 bool failed = false;
942 for (RelocIterator it(code, mode); !it.done(); it.next()) {
943 RelocInfo* rinfo = it.rinfo();
944 Address address = rinfo->target_external_reference();
945 const Runtime::Function* function = Runtime::FunctionForEntry(address);
946 if (function == nullptr) continue;
947 if (!BuiltinToIntrinsicHasNoSideEffect(
948 static_cast<Builtins::Name>(builtin_index),
949 function->function_id)) {
950 PrintF("Whitelisted builtin %s calls non-whitelisted intrinsic %s\n",
951 Builtins::name(builtin_index), function->name);
952 failed = true;
953 }
954 DCHECK(!failed);
955 }
956 }
957 #endif // DEBUG
958 return state;
959 }
960
961 return DebugInfo::kHasSideEffects;
962 }
963
964 // static
CallbackHasNoSideEffect(Object * callback_info)965 bool DebugEvaluate::CallbackHasNoSideEffect(Object* callback_info) {
966 DisallowHeapAllocation no_gc;
967 if (callback_info->IsAccessorInfo()) {
968 // List of whitelisted internal accessors can be found in accessors.h.
969 AccessorInfo* info = AccessorInfo::cast(callback_info);
970 if (info->has_no_side_effect()) return true;
971 if (FLAG_trace_side_effect_free_debug_evaluate) {
972 PrintF("[debug-evaluate] API Callback '");
973 info->name()->ShortPrint();
974 PrintF("' may cause side effect.\n");
975 }
976 } else if (callback_info->IsInterceptorInfo()) {
977 InterceptorInfo* info = InterceptorInfo::cast(callback_info);
978 if (info->has_no_side_effect()) return true;
979 if (FLAG_trace_side_effect_free_debug_evaluate) {
980 PrintF("[debug-evaluate] API Interceptor may cause side effect.\n");
981 }
982 } else if (callback_info->IsCallHandlerInfo()) {
983 CallHandlerInfo* info = CallHandlerInfo::cast(callback_info);
984 if (info->IsSideEffectFreeCallHandlerInfo()) return true;
985 if (FLAG_trace_side_effect_free_debug_evaluate) {
986 PrintF("[debug-evaluate] API CallHandlerInfo may cause side effect.\n");
987 }
988 }
989 return false;
990 }
991
992 // static
ApplySideEffectChecks(Handle<BytecodeArray> bytecode_array)993 void DebugEvaluate::ApplySideEffectChecks(
994 Handle<BytecodeArray> bytecode_array) {
995 for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
996 it.Advance()) {
997 interpreter::Bytecode bytecode = it.current_bytecode();
998 if (BytecodeRequiresRuntimeCheck(bytecode)) it.ApplyDebugBreak();
999 }
1000 }
1001
1002 } // namespace internal
1003 } // namespace v8
1004