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