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