Line data Source code
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 :
20 : namespace v8 {
21 : namespace internal {
22 :
23 10 : static inline bool IsDebugContext(Isolate* isolate, Context* context) {
24 : return context->native_context() == *isolate->debug()->debug_context();
25 : }
26 :
27 5 : MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
28 : Handle<String> source) {
29 : // Handle the processing of break.
30 : DisableBreak disable_break_scope(isolate->debug());
31 :
32 : // Enter the top context from before the debugger was invoked.
33 10 : SaveContext save(isolate);
34 5 : SaveContext* top = &save;
35 25 : while (top != nullptr && IsDebugContext(isolate, *top->context())) {
36 : top = top->prev();
37 : }
38 5 : if (top != nullptr) isolate->set_context(*top->context());
39 :
40 : // Get the native context now set to the top context from before the
41 : // debugger was invoked.
42 5 : Handle<Context> context = isolate->native_context();
43 5 : Handle<JSObject> receiver(context->global_proxy());
44 : Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
45 10 : return Evaluate(isolate, outer_info, context, receiver, source, false);
46 : }
47 :
48 10491 : MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
49 : StackFrame::Id frame_id,
50 : int inlined_jsframe_index,
51 : Handle<String> source,
52 : bool throw_on_side_effect) {
53 : // Handle the processing of break.
54 : DisableBreak disable_break_scope(isolate->debug());
55 :
56 : // Get the frame where the debugging is performed.
57 10491 : StackTraceFrameIterator it(isolate, frame_id);
58 10491 : if (!it.is_javascript()) return isolate->factory()->undefined_value();
59 : JavaScriptFrame* frame = it.javascript_frame();
60 :
61 : // Traverse the saved contexts chain to find the active context for the
62 : // selected frame.
63 : SaveContext* save =
64 10491 : DebugFrameHelper::FindSavedContextForFrame(isolate, frame);
65 20982 : SaveContext savex(isolate);
66 : isolate->set_context(*(save->context()));
67 :
68 : // This is not a lot different than DebugEvaluate::Global, except that
69 : // variables accessible by the function we are evaluating from are
70 : // materialized and included on top of the native context. Changes to
71 : // the materialized object are written back afterwards.
72 : // Note that the native context is taken from the original context chain,
73 : // which may not be the current native context of the isolate.
74 10491 : ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
75 10491 : if (isolate->has_pending_exception()) return MaybeHandle<Object>();
76 :
77 : Handle<Context> context = context_builder.evaluation_context();
78 10491 : Handle<JSObject> receiver(context->global_proxy());
79 : MaybeHandle<Object> maybe_result =
80 : Evaluate(isolate, context_builder.outer_info(), context, receiver, source,
81 20982 : throw_on_side_effect);
82 10491 : if (!maybe_result.is_null()) context_builder.UpdateValues();
83 10491 : return maybe_result;
84 : }
85 :
86 :
87 : // Compile and evaluate source for the given context.
88 10496 : MaybeHandle<Object> DebugEvaluate::Evaluate(
89 : Isolate* isolate, Handle<SharedFunctionInfo> outer_info,
90 : Handle<Context> context, Handle<Object> receiver, Handle<String> source,
91 : bool throw_on_side_effect) {
92 : Handle<JSFunction> eval_fun;
93 20992 : ASSIGN_RETURN_ON_EXCEPTION(
94 : isolate, eval_fun,
95 : Compiler::GetFunctionFromEval(source, outer_info, context,
96 : LanguageMode::kSloppy, NO_PARSE_RESTRICTION,
97 : kNoSourcePosition, kNoSourcePosition,
98 : kNoSourcePosition),
99 : Object);
100 :
101 : Handle<Object> result;
102 : {
103 10432 : NoSideEffectScope no_side_effect(isolate, throw_on_side_effect);
104 20864 : ASSIGN_RETURN_ON_EXCEPTION(
105 : isolate, result,
106 9566 : Execution::Call(isolate, eval_fun, receiver, 0, nullptr), Object);
107 : }
108 :
109 : // Skip the global proxy as it has no properties and always delegates to the
110 : // real global object.
111 9566 : if (result->IsJSGlobalProxy()) {
112 18 : PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result));
113 : // TODO(verwaest): This will crash when the global proxy is detached.
114 : result = PrototypeIterator::GetCurrent<JSObject>(iter);
115 : }
116 :
117 9566 : return result;
118 : }
119 :
120 :
121 10491 : DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
122 : JavaScriptFrame* frame,
123 : int inlined_jsframe_index)
124 : : isolate_(isolate),
125 : frame_(frame),
126 10491 : inlined_jsframe_index_(inlined_jsframe_index) {
127 10491 : FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
128 : Handle<JSFunction> local_function = frame_inspector.GetFunction();
129 : Handle<Context> outer_context(local_function->context());
130 10491 : evaluation_context_ = outer_context;
131 10491 : outer_info_ = handle(local_function->shared());
132 : Factory* factory = isolate->factory();
133 :
134 : // To evaluate as if we were running eval at the point of the debug break,
135 : // we reconstruct the context chain as follows:
136 : // - To make stack-allocated variables visible, we materialize them and
137 : // use a debug-evaluate context to wrap both the materialized object and
138 : // the original context.
139 : // - We use the original context chain from the function context to the
140 : // native context.
141 : // - Between the function scope and the native context, we only resolve
142 : // variable names that the current function already uses. Only for these
143 : // names we can be sure that they will be correctly resolved. For the
144 : // rest, we only resolve to with, script, and native contexts. We use a
145 : // whitelist to implement that.
146 : // Context::Lookup has special handling for debug-evaluate contexts:
147 : // - Look up in the materialized stack variables.
148 : // - Look up in the original context.
149 : // - Check the whitelist to find out whether to skip contexts during lookup.
150 : const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS;
151 21726 : for (ScopeIterator it(isolate, &frame_inspector, option); !it.Done();
152 744 : it.Next()) {
153 11225 : ScopeIterator::ScopeType scope_type = it.Type();
154 11225 : if (scope_type == ScopeIterator::ScopeTypeLocal) {
155 : DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
156 10148 : Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
157 : Handle<Context> local_context =
158 10148 : it.HasContext() ? it.CurrentContext() : outer_context;
159 10148 : Handle<StringSet> non_locals = it.GetNonLocals();
160 : MaterializeReceiver(materialized, local_context, local_function,
161 10148 : non_locals);
162 : frame_inspector.MaterializeStackLocals(materialized, local_function,
163 10148 : true);
164 : ContextChainElement context_chain_element;
165 10148 : context_chain_element.scope_info = it.CurrentScopeInfo();
166 10148 : context_chain_element.materialized_object = materialized;
167 : // Non-locals that are already being referenced by the current function
168 : // are guaranteed to be correctly resolved.
169 10148 : context_chain_element.whitelist = non_locals;
170 10148 : if (it.HasContext()) {
171 517 : context_chain_element.wrapped_context = it.CurrentContext();
172 : }
173 10148 : context_chain_.push_back(context_chain_element);
174 10148 : evaluation_context_ = outer_context;
175 : break;
176 2154 : } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
177 1889 : scope_type == ScopeIterator::ScopeTypeWith ||
178 : scope_type == ScopeIterator::ScopeTypeModule) {
179 : ContextChainElement context_chain_element;
180 450 : Handle<Context> current_context = it.CurrentContext();
181 450 : if (!current_context->IsDebugEvaluateContext()) {
182 450 : context_chain_element.wrapped_context = current_context;
183 : }
184 450 : context_chain_.push_back(context_chain_element);
185 1254 : } else if (scope_type == ScopeIterator::ScopeTypeBlock ||
186 627 : scope_type == ScopeIterator::ScopeTypeEval) {
187 294 : Handle<JSObject> materialized = factory->NewJSObjectWithNullProto();
188 : frame_inspector.MaterializeStackLocals(materialized,
189 294 : it.CurrentScopeInfo());
190 : ContextChainElement context_chain_element;
191 294 : context_chain_element.scope_info = it.CurrentScopeInfo();
192 294 : context_chain_element.materialized_object = materialized;
193 294 : if (it.HasContext()) {
194 50 : context_chain_element.wrapped_context = it.CurrentContext();
195 : }
196 294 : context_chain_.push_back(context_chain_element);
197 : } else {
198 : break;
199 : }
200 : }
201 :
202 21383 : for (auto rit = context_chain_.rbegin(); rit != context_chain_.rend();
203 : rit++) {
204 10892 : ContextChainElement element = *rit;
205 : Handle<ScopeInfo> scope_info(ScopeInfo::CreateForWithScope(
206 10892 : isolate, evaluation_context_->IsNativeContext()
207 : ? Handle<ScopeInfo>::null()
208 23756 : : Handle<ScopeInfo>(evaluation_context_->scope_info())));
209 10892 : scope_info->SetIsDebugEvaluateScope();
210 : evaluation_context_ = factory->NewDebugEvaluateContext(
211 : evaluation_context_, scope_info, element.materialized_object,
212 10892 : element.wrapped_context, element.whitelist);
213 10491 : }
214 10491 : }
215 :
216 :
217 9561 : void DebugEvaluate::ContextBuilder::UpdateValues() {
218 29094 : for (ContextChainElement& element : context_chain_) {
219 9972 : if (!element.materialized_object.is_null()) {
220 : // Write back potential changes to materialized stack locals to the stack.
221 : FrameInspector(frame_, inlined_jsframe_index_, isolate_)
222 : .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
223 9542 : element.scope_info);
224 : }
225 : }
226 9561 : }
227 :
228 :
229 10148 : void DebugEvaluate::ContextBuilder::MaterializeReceiver(
230 : Handle<JSObject> target, Handle<Context> local_context,
231 : Handle<JSFunction> local_function, Handle<StringSet> non_locals) {
232 10148 : Handle<Object> recv = isolate_->factory()->undefined_value();
233 : Handle<String> name = isolate_->factory()->this_string();
234 10148 : if (non_locals->Has(name)) {
235 : // 'this' is allocated in an outer context and is is already being
236 : // referenced by the current function, so it can be correctly resolved.
237 234 : return;
238 19433 : } else if (local_function->shared()->scope_info()->HasReceiver() &&
239 9519 : !frame_->receiver()->IsTheHole(isolate_)) {
240 19020 : recv = handle(frame_->receiver(), isolate_);
241 : }
242 19828 : JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check();
243 : }
244 :
245 : namespace {
246 :
247 2259 : bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
248 : // Use macro to include both inlined and non-inlined version of an intrinsic.
249 : #define INTRINSIC_WHITELIST(V) \
250 : /* Conversions */ \
251 : V(ToInteger) \
252 : V(ToObject) \
253 : V(ToString) \
254 : V(ToLength) \
255 : V(ToNumber) \
256 : V(NumberToString) \
257 : /* Type checks */ \
258 : V(IsJSReceiver) \
259 : V(IsSmi) \
260 : V(IsArray) \
261 : V(IsFunction) \
262 : V(IsDate) \
263 : V(IsJSProxy) \
264 : V(IsJSMap) \
265 : V(IsJSSet) \
266 : V(IsJSWeakMap) \
267 : V(IsJSWeakSet) \
268 : V(IsRegExp) \
269 : V(IsTypedArray) \
270 : V(ClassOf) \
271 : /* Loads */ \
272 : V(LoadLookupSlotForCall) \
273 : /* Arrays */ \
274 : V(ArraySpeciesConstructor) \
275 : V(NormalizeElements) \
276 : V(GetArrayKeys) \
277 : V(HasComplexElements) \
278 : V(EstimateNumberOfElements) \
279 : /* Errors */ \
280 : V(ReThrow) \
281 : V(ThrowReferenceError) \
282 : V(ThrowSymbolIteratorInvalid) \
283 : V(ThrowIteratorResultNotAnObject) \
284 : V(NewTypeError) \
285 : V(ThrowInvalidStringLength) \
286 : /* Strings */ \
287 : V(StringIndexOf) \
288 : V(StringIncludes) \
289 : V(StringReplaceOneCharWithString) \
290 : V(StringToNumber) \
291 : V(StringTrim) \
292 : V(SubString) \
293 : V(RegExpInternalReplace) \
294 : /* BigInts */ \
295 : V(BigIntEqual) \
296 : V(BigIntToBoolean) \
297 : /* Literals */ \
298 : V(CreateArrayLiteral) \
299 : V(CreateObjectLiteral) \
300 : V(CreateRegExpLiteral) \
301 : /* Collections */ \
302 : V(GenericHash) \
303 : /* Called from builtins */ \
304 : V(StringAdd) \
305 : V(StringParseFloat) \
306 : V(StringParseInt) \
307 : V(StringCharCodeAt) \
308 : V(StringIndexOfUnchecked) \
309 : V(StringEqual) \
310 : V(RegExpInitializeAndCompile) \
311 : V(SymbolDescriptiveString) \
312 : V(GenerateRandomNumbers) \
313 : V(GlobalPrint) \
314 : V(AllocateInNewSpace) \
315 : V(AllocateSeqOneByteString) \
316 : V(AllocateSeqTwoByteString) \
317 : V(ObjectCreate) \
318 : V(ObjectHasOwnProperty) \
319 : V(ArrayIndexOf) \
320 : V(ArrayIncludes_Slow) \
321 : V(ArrayIsArray) \
322 : V(ThrowTypeError) \
323 : V(ThrowCalledOnNullOrUndefined) \
324 : V(ThrowIncompatibleMethodReceiver) \
325 : V(ThrowInvalidHint) \
326 : V(ThrowNotDateError) \
327 : V(ThrowRangeError) \
328 : V(ToName) \
329 : V(GetOwnPropertyDescriptor) \
330 : /* Misc. */ \
331 : V(Call) \
332 : V(MaxSmi) \
333 : V(NewObject) \
334 : V(FinalizeInstanceSize) \
335 : V(HasInPrototypeChain) \
336 : V(StringMaxLength)
337 :
338 : #define CASE(Name) \
339 : case Runtime::k##Name: \
340 : case Runtime::kInline##Name:
341 :
342 2259 : switch (id) {
343 : INTRINSIC_WHITELIST(CASE)
344 : return true;
345 : default:
346 465 : if (FLAG_trace_side_effect_free_debug_evaluate) {
347 : PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n",
348 0 : Runtime::FunctionForId(id)->name);
349 : }
350 : return false;
351 : }
352 :
353 : #undef CASE
354 : #undef INTRINSIC_WHITELIST
355 : }
356 :
357 62700 : bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
358 : typedef interpreter::Bytecode Bytecode;
359 : typedef interpreter::Bytecodes Bytecodes;
360 62700 : if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
361 25015 : if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
362 20244 : if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
363 19728 : if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
364 19728 : switch (bytecode) {
365 : // Whitelist for bytecodes.
366 : // Loads.
367 : case Bytecode::kLdaLookupSlot:
368 : case Bytecode::kLdaGlobal:
369 : case Bytecode::kLdaNamedProperty:
370 : case Bytecode::kLdaKeyedProperty:
371 : // Arithmetics.
372 : case Bytecode::kAdd:
373 : case Bytecode::kAddSmi:
374 : case Bytecode::kSub:
375 : case Bytecode::kSubSmi:
376 : case Bytecode::kMul:
377 : case Bytecode::kMulSmi:
378 : case Bytecode::kDiv:
379 : case Bytecode::kDivSmi:
380 : case Bytecode::kMod:
381 : case Bytecode::kModSmi:
382 : case Bytecode::kNegate:
383 : case Bytecode::kBitwiseAnd:
384 : case Bytecode::kBitwiseAndSmi:
385 : case Bytecode::kBitwiseNot:
386 : case Bytecode::kBitwiseOr:
387 : case Bytecode::kBitwiseOrSmi:
388 : case Bytecode::kBitwiseXor:
389 : case Bytecode::kBitwiseXorSmi:
390 : case Bytecode::kShiftLeft:
391 : case Bytecode::kShiftLeftSmi:
392 : case Bytecode::kShiftRight:
393 : case Bytecode::kShiftRightSmi:
394 : case Bytecode::kShiftRightLogical:
395 : case Bytecode::kShiftRightLogicalSmi:
396 : case Bytecode::kInc:
397 : case Bytecode::kDec:
398 : case Bytecode::kLogicalNot:
399 : case Bytecode::kToBooleanLogicalNot:
400 : case Bytecode::kTypeOf:
401 : // Contexts.
402 : case Bytecode::kCreateBlockContext:
403 : case Bytecode::kCreateCatchContext:
404 : case Bytecode::kCreateFunctionContext:
405 : case Bytecode::kCreateEvalContext:
406 : case Bytecode::kCreateWithContext:
407 : // Literals.
408 : case Bytecode::kCreateArrayLiteral:
409 : case Bytecode::kCreateEmptyArrayLiteral:
410 : case Bytecode::kCreateObjectLiteral:
411 : case Bytecode::kCreateEmptyObjectLiteral:
412 : case Bytecode::kCreateRegExpLiteral:
413 : // Allocations.
414 : case Bytecode::kCreateClosure:
415 : case Bytecode::kCreateUnmappedArguments:
416 : case Bytecode::kCreateRestParameter:
417 : // Comparisons.
418 : case Bytecode::kTestEqual:
419 : case Bytecode::kTestEqualStrict:
420 : case Bytecode::kTestLessThan:
421 : case Bytecode::kTestLessThanOrEqual:
422 : case Bytecode::kTestGreaterThan:
423 : case Bytecode::kTestGreaterThanOrEqual:
424 : case Bytecode::kTestInstanceOf:
425 : case Bytecode::kTestIn:
426 : case Bytecode::kTestEqualStrictNoFeedback:
427 : case Bytecode::kTestUndetectable:
428 : case Bytecode::kTestTypeOf:
429 : case Bytecode::kTestUndefined:
430 : case Bytecode::kTestNull:
431 : // Conversions.
432 : case Bytecode::kToObject:
433 : case Bytecode::kToNumber:
434 : case Bytecode::kToName:
435 : // Misc.
436 : case Bytecode::kForInEnumerate:
437 : case Bytecode::kForInPrepare:
438 : case Bytecode::kForInContinue:
439 : case Bytecode::kForInNext:
440 : case Bytecode::kForInStep:
441 : case Bytecode::kThrow:
442 : case Bytecode::kReThrow:
443 : case Bytecode::kThrowReferenceErrorIfHole:
444 : case Bytecode::kThrowSuperNotCalledIfHole:
445 : case Bytecode::kThrowSuperAlreadyCalledIfNotHole:
446 : case Bytecode::kIllegal:
447 : case Bytecode::kCallJSRuntime:
448 : case Bytecode::kStackCheck:
449 : case Bytecode::kReturn:
450 : case Bytecode::kSetPendingMessage:
451 : return true;
452 : default:
453 387 : if (FLAG_trace_side_effect_free_debug_evaluate) {
454 : PrintF("[debug-evaluate] bytecode %s may cause side effect.\n",
455 0 : Bytecodes::ToString(bytecode));
456 : }
457 : return false;
458 : }
459 : }
460 :
461 3744 : bool BuiltinHasNoSideEffect(Builtins::Name id) {
462 3744 : switch (id) {
463 : // Whitelist for builtins.
464 : // Object builtins.
465 : case Builtins::kObjectConstructor:
466 : case Builtins::kObjectCreate:
467 : case Builtins::kObjectEntries:
468 : case Builtins::kObjectGetOwnPropertyDescriptor:
469 : case Builtins::kObjectGetOwnPropertyDescriptors:
470 : case Builtins::kObjectGetOwnPropertyNames:
471 : case Builtins::kObjectGetOwnPropertySymbols:
472 : case Builtins::kObjectGetPrototypeOf:
473 : case Builtins::kObjectIs:
474 : case Builtins::kObjectIsExtensible:
475 : case Builtins::kObjectIsFrozen:
476 : case Builtins::kObjectIsSealed:
477 : case Builtins::kObjectPrototypeValueOf:
478 : case Builtins::kObjectValues:
479 : case Builtins::kObjectPrototypeHasOwnProperty:
480 : case Builtins::kObjectPrototypeIsPrototypeOf:
481 : case Builtins::kObjectPrototypePropertyIsEnumerable:
482 : case Builtins::kObjectPrototypeToString:
483 : // Array builtins.
484 : case Builtins::kArrayConstructor:
485 : case Builtins::kArrayIndexOf:
486 : case Builtins::kArrayPrototypeValues:
487 : case Builtins::kArrayIncludes:
488 : case Builtins::kArrayPrototypeEntries:
489 : case Builtins::kArrayPrototypeKeys:
490 : case Builtins::kArrayForEach:
491 : case Builtins::kArrayEvery:
492 : case Builtins::kArraySome:
493 : case Builtins::kArrayReduce:
494 : case Builtins::kArrayReduceRight:
495 : // Boolean bulitins.
496 : case Builtins::kBooleanConstructor:
497 : case Builtins::kBooleanPrototypeToString:
498 : case Builtins::kBooleanPrototypeValueOf:
499 : // Date builtins.
500 : case Builtins::kDateConstructor:
501 : case Builtins::kDateNow:
502 : case Builtins::kDateParse:
503 : case Builtins::kDatePrototypeGetDate:
504 : case Builtins::kDatePrototypeGetDay:
505 : case Builtins::kDatePrototypeGetFullYear:
506 : case Builtins::kDatePrototypeGetHours:
507 : case Builtins::kDatePrototypeGetMilliseconds:
508 : case Builtins::kDatePrototypeGetMinutes:
509 : case Builtins::kDatePrototypeGetMonth:
510 : case Builtins::kDatePrototypeGetSeconds:
511 : case Builtins::kDatePrototypeGetTime:
512 : case Builtins::kDatePrototypeGetTimezoneOffset:
513 : case Builtins::kDatePrototypeGetUTCDate:
514 : case Builtins::kDatePrototypeGetUTCDay:
515 : case Builtins::kDatePrototypeGetUTCFullYear:
516 : case Builtins::kDatePrototypeGetUTCHours:
517 : case Builtins::kDatePrototypeGetUTCMilliseconds:
518 : case Builtins::kDatePrototypeGetUTCMinutes:
519 : case Builtins::kDatePrototypeGetUTCMonth:
520 : case Builtins::kDatePrototypeGetUTCSeconds:
521 : case Builtins::kDatePrototypeGetYear:
522 : case Builtins::kDatePrototypeToDateString:
523 : case Builtins::kDatePrototypeToISOString:
524 : case Builtins::kDatePrototypeToUTCString:
525 : case Builtins::kDatePrototypeToString:
526 : case Builtins::kDatePrototypeToTimeString:
527 : case Builtins::kDatePrototypeToJson:
528 : case Builtins::kDatePrototypeToPrimitive:
529 : case Builtins::kDatePrototypeValueOf:
530 : // Map builtins.
531 : case Builtins::kMapConstructor:
532 : case Builtins::kMapPrototypeGet:
533 : case Builtins::kMapPrototypeEntries:
534 : case Builtins::kMapPrototypeGetSize:
535 : case Builtins::kMapPrototypeKeys:
536 : case Builtins::kMapPrototypeValues:
537 : // Math builtins.
538 : case Builtins::kMathAbs:
539 : case Builtins::kMathAcos:
540 : case Builtins::kMathAcosh:
541 : case Builtins::kMathAsin:
542 : case Builtins::kMathAsinh:
543 : case Builtins::kMathAtan:
544 : case Builtins::kMathAtanh:
545 : case Builtins::kMathAtan2:
546 : case Builtins::kMathCeil:
547 : case Builtins::kMathCbrt:
548 : case Builtins::kMathExpm1:
549 : case Builtins::kMathClz32:
550 : case Builtins::kMathCos:
551 : case Builtins::kMathCosh:
552 : case Builtins::kMathExp:
553 : case Builtins::kMathFloor:
554 : case Builtins::kMathFround:
555 : case Builtins::kMathHypot:
556 : case Builtins::kMathImul:
557 : case Builtins::kMathLog:
558 : case Builtins::kMathLog1p:
559 : case Builtins::kMathLog2:
560 : case Builtins::kMathLog10:
561 : case Builtins::kMathMax:
562 : case Builtins::kMathMin:
563 : case Builtins::kMathPow:
564 : case Builtins::kMathRandom:
565 : case Builtins::kMathRound:
566 : case Builtins::kMathSign:
567 : case Builtins::kMathSin:
568 : case Builtins::kMathSinh:
569 : case Builtins::kMathSqrt:
570 : case Builtins::kMathTan:
571 : case Builtins::kMathTanh:
572 : case Builtins::kMathTrunc:
573 : // Number builtins.
574 : case Builtins::kNumberConstructor:
575 : case Builtins::kNumberIsFinite:
576 : case Builtins::kNumberIsInteger:
577 : case Builtins::kNumberIsNaN:
578 : case Builtins::kNumberIsSafeInteger:
579 : case Builtins::kNumberParseFloat:
580 : case Builtins::kNumberParseInt:
581 : case Builtins::kNumberPrototypeToExponential:
582 : case Builtins::kNumberPrototypeToFixed:
583 : case Builtins::kNumberPrototypeToPrecision:
584 : case Builtins::kNumberPrototypeToString:
585 : case Builtins::kNumberPrototypeValueOf:
586 : // Set builtins.
587 : case Builtins::kSetConstructor:
588 : case Builtins::kSetPrototypeEntries:
589 : case Builtins::kSetPrototypeGetSize:
590 : case Builtins::kSetPrototypeValues:
591 : // String builtins. Strings are immutable.
592 : case Builtins::kStringFromCharCode:
593 : case Builtins::kStringFromCodePoint:
594 : case Builtins::kStringConstructor:
595 : case Builtins::kStringPrototypeAnchor:
596 : case Builtins::kStringPrototypeBig:
597 : case Builtins::kStringPrototypeBlink:
598 : case Builtins::kStringPrototypeBold:
599 : case Builtins::kStringPrototypeCharAt:
600 : case Builtins::kStringPrototypeCharCodeAt:
601 : case Builtins::kStringPrototypeCodePointAt:
602 : case Builtins::kStringPrototypeConcat:
603 : case Builtins::kStringPrototypeEndsWith:
604 : case Builtins::kStringPrototypeFixed:
605 : case Builtins::kStringPrototypeFontcolor:
606 : case Builtins::kStringPrototypeFontsize:
607 : case Builtins::kStringPrototypeIncludes:
608 : case Builtins::kStringPrototypeIndexOf:
609 : case Builtins::kStringPrototypeItalics:
610 : case Builtins::kStringPrototypeLastIndexOf:
611 : case Builtins::kStringPrototypeLink:
612 : case Builtins::kStringPrototypePadEnd:
613 : case Builtins::kStringPrototypePadStart:
614 : case Builtins::kStringPrototypeRepeat:
615 : case Builtins::kStringPrototypeSlice:
616 : case Builtins::kStringPrototypeSmall:
617 : case Builtins::kStringPrototypeStartsWith:
618 : case Builtins::kStringPrototypeStrike:
619 : case Builtins::kStringPrototypeSub:
620 : case Builtins::kStringPrototypeSubstr:
621 : case Builtins::kStringPrototypeSubstring:
622 : case Builtins::kStringPrototypeSup:
623 : case Builtins::kStringPrototypeToString:
624 : #ifndef V8_INTL_SUPPORT
625 : case Builtins::kStringPrototypeToLowerCase:
626 : case Builtins::kStringPrototypeToUpperCase:
627 : #endif
628 : case Builtins::kStringPrototypeTrim:
629 : case Builtins::kStringPrototypeTrimLeft:
630 : case Builtins::kStringPrototypeTrimRight:
631 : case Builtins::kStringPrototypeValueOf:
632 : case Builtins::kStringToNumber:
633 : case Builtins::kSubString:
634 : // Symbol builtins.
635 : case Builtins::kSymbolConstructor:
636 : case Builtins::kSymbolKeyFor:
637 : case Builtins::kSymbolPrototypeToString:
638 : case Builtins::kSymbolPrototypeValueOf:
639 : case Builtins::kSymbolPrototypeToPrimitive:
640 : // JSON builtins.
641 : case Builtins::kJsonParse:
642 : case Builtins::kJsonStringify:
643 : // Global function builtins.
644 : case Builtins::kGlobalDecodeURI:
645 : case Builtins::kGlobalDecodeURIComponent:
646 : case Builtins::kGlobalEncodeURI:
647 : case Builtins::kGlobalEncodeURIComponent:
648 : case Builtins::kGlobalEscape:
649 : case Builtins::kGlobalUnescape:
650 : case Builtins::kGlobalIsFinite:
651 : case Builtins::kGlobalIsNaN:
652 : // Error builtins.
653 : case Builtins::kMakeError:
654 : case Builtins::kMakeTypeError:
655 : case Builtins::kMakeSyntaxError:
656 : case Builtins::kMakeRangeError:
657 : case Builtins::kMakeURIError:
658 : return true;
659 : default:
660 1994 : if (FLAG_trace_side_effect_free_debug_evaluate) {
661 : PrintF("[debug-evaluate] built-in %s may cause side effect.\n",
662 0 : Builtins::name(id));
663 : }
664 : return false;
665 : }
666 : }
667 :
668 : static const Address accessors_with_no_side_effect[] = {
669 : // Whitelist for accessors.
670 : FUNCTION_ADDR(Accessors::StringLengthGetter),
671 : FUNCTION_ADDR(Accessors::ArrayLengthGetter),
672 : FUNCTION_ADDR(Accessors::FunctionLengthGetter),
673 : FUNCTION_ADDR(Accessors::FunctionNameGetter),
674 : FUNCTION_ADDR(Accessors::BoundFunctionLengthGetter),
675 : FUNCTION_ADDR(Accessors::BoundFunctionNameGetter),
676 : };
677 :
678 : } // anonymous namespace
679 :
680 : // static
681 8181 : bool DebugEvaluate::FunctionHasNoSideEffect(Handle<SharedFunctionInfo> info) {
682 8181 : if (FLAG_trace_side_effect_free_debug_evaluate) {
683 : PrintF("[debug-evaluate] Checking function %s for side effect.\n",
684 0 : info->DebugName()->ToCString().get());
685 : }
686 :
687 : DCHECK(info->is_compiled());
688 :
689 8181 : if (info->HasBytecodeArray()) {
690 : // Check bytecodes against whitelist.
691 : Handle<BytecodeArray> bytecode_array(info->bytecode_array());
692 4437 : if (FLAG_trace_side_effect_free_debug_evaluate) bytecode_array->Print();
693 72981 : for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done();
694 64107 : it.Advance()) {
695 64959 : interpreter::Bytecode bytecode = it.current_bytecode();
696 :
697 64959 : if (interpreter::Bytecodes::IsCallRuntime(bytecode)) {
698 : Runtime::FunctionId id =
699 : (bytecode == interpreter::Bytecode::kInvokeIntrinsic)
700 : ? it.GetIntrinsicIdOperand(0)
701 2259 : : it.GetRuntimeIdOperand(0);
702 2259 : if (IntrinsicHasNoSideEffect(id)) continue;
703 852 : return false;
704 : }
705 :
706 62700 : if (BytecodeHasNoSideEffect(bytecode)) continue;
707 :
708 : // Did not match whitelist.
709 : return false;
710 : }
711 3585 : return true;
712 : } else {
713 : // Check built-ins against whitelist.
714 : int builtin_index = info->HasLazyDeserializationBuiltinId()
715 : ? info->lazy_deserialization_builtin_id()
716 3744 : : info->code()->builtin_index();
717 : DCHECK_NE(Builtins::kDeserializeLazy, builtin_index);
718 7488 : if (builtin_index >= 0 && builtin_index < Builtins::builtin_count &&
719 3744 : BuiltinHasNoSideEffect(static_cast<Builtins::Name>(builtin_index))) {
720 : #ifdef DEBUG
721 : if (info->code()->builtin_index() == Builtins::kDeserializeLazy) {
722 : return true; // Target builtin is not yet deserialized.
723 : }
724 : // TODO(yangguo): Check builtin-to-builtin calls too.
725 : int mode = RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE);
726 : bool failed = false;
727 : for (RelocIterator it(info->code(), mode); !it.done(); it.next()) {
728 : RelocInfo* rinfo = it.rinfo();
729 : Address address = rinfo->target_external_reference();
730 : const Runtime::Function* function = Runtime::FunctionForEntry(address);
731 : if (function == nullptr) continue;
732 : if (!IntrinsicHasNoSideEffect(function->function_id)) {
733 : PrintF("Whitelisted builtin %s calls non-whitelisted intrinsic %s\n",
734 : Builtins::name(builtin_index), function->name);
735 : failed = true;
736 : }
737 : DCHECK(!failed);
738 : }
739 : #endif // DEBUG
740 : return true;
741 : }
742 : }
743 :
744 1994 : return false;
745 : }
746 :
747 : // static
748 70 : bool DebugEvaluate::CallbackHasNoSideEffect(Address function_addr) {
749 259 : for (size_t i = 0; i < arraysize(accessors_with_no_side_effect); i++) {
750 250 : if (function_addr == accessors_with_no_side_effect[i]) return true;
751 : }
752 :
753 9 : if (FLAG_trace_side_effect_free_debug_evaluate) {
754 : PrintF("[debug-evaluate] API Callback at %p may cause side effect.\n",
755 0 : reinterpret_cast<void*>(function_addr));
756 : }
757 : return false;
758 : }
759 :
760 : } // namespace internal
761 : } // namespace v8
|