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

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

Issue 1500933002: [debugger] fix debug-evaluate wrt shadowed context var. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: test case Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/debug/debug-evaluate.h" 5 #include "src/debug/debug-evaluate.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/contexts.h" 8 #include "src/contexts.h"
9 #include "src/debug/debug.h" 9 #include "src/debug/debug.h"
10 #include "src/debug/debug-frames.h" 10 #include "src/debug/debug-frames.h"
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 if (result->IsJSGlobalProxy()) { 105 if (result->IsJSGlobalProxy()) {
106 PrototypeIterator iter(isolate, result); 106 PrototypeIterator iter(isolate, result);
107 // TODO(verwaest): This will crash when the global proxy is detached. 107 // TODO(verwaest): This will crash when the global proxy is detached.
108 result = PrototypeIterator::GetCurrent<JSObject>(iter); 108 result = PrototypeIterator::GetCurrent<JSObject>(iter);
109 } 109 }
110 110
111 return result; 111 return result;
112 } 112 }
113 113
114 114
115 Handle<Context> FindScriptOrNativeContext(Handle<Context> context) {
116 DisallowHeapAllocation no_gc;
117 Context* raw_context = *context;
118 while (!raw_context->IsScriptContext() && !raw_context->IsNativeContext()) {
119 raw_context = raw_context->previous();
120 }
121 return Handle<Context>(raw_context);
122 }
123
124
115 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, 125 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
116 JavaScriptFrame* frame, 126 JavaScriptFrame* frame,
117 int inlined_jsframe_index) 127 int inlined_jsframe_index)
118 : isolate_(isolate), 128 : isolate_(isolate),
119 frame_(frame), 129 frame_(frame),
120 inlined_jsframe_index_(inlined_jsframe_index) { 130 inlined_jsframe_index_(inlined_jsframe_index) {
121 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 131 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
122 Handle<JSFunction> function = 132 Handle<JSFunction> function =
123 handle(JSFunction::cast(frame_inspector.GetFunction())); 133 handle(JSFunction::cast(frame_inspector.GetFunction()));
124 Handle<Context> outer_context = handle(function->context(), isolate); 134 Handle<Context> outer_context = handle(function->context(), isolate);
125 outer_info_ = handle(function->shared()); 135 outer_info_ = handle(function->shared());
126 Handle<Context> inner_context; 136 Handle<Context> inner_context;
127 137
128 bool stop = false; 138 bool stop = false;
129 for (ScopeIterator it(isolate, &frame_inspector); 139 const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS;
140 for (ScopeIterator it(isolate, &frame_inspector, option);
130 !it.Failed() && !it.Done() && !stop; it.Next()) { 141 !it.Failed() && !it.Done() && !stop; it.Next()) {
131 ScopeIterator::ScopeType scope_type = it.Type(); 142 ScopeIterator::ScopeType scope_type = it.Type();
132 143
144 // Duplicate contexts up to the script context for debug evaluate.
145 // The content of the duplicated contexts are written back to the original
146 // at the end. This however means that any changes to the original will be
147 // overwritten.
133 if (scope_type == ScopeIterator::ScopeTypeLocal) { 148 if (scope_type == ScopeIterator::ScopeTypeLocal) {
134 Handle<Context> parent_context = 149 // The context chain at this point looks like this:
150 // <native context> <script context> <outer contexts>
151 // <function context> <inner contexts>
152 // We can only be sure to correctly resolve variables that our function
153 // itself already references. Other variables may be stack-allocated,
154 // and invisible to the context lookup.
155 // To make sure that other variables are not accessible, we collect the
156 // variables used by our function and replace the context chain between
157 // the current function and the script context by a with-context that
158 // materializes accessible context vars and stack vars. We also add a
159 // catch-context to resolve 'this' if necessary.
160 // After the replacement, it looks like this:
161 // <native context> <script context> <receiver context>
162 // <accessible context vars and materialized stack> <inner contexts>
163 DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
164 it.GetNonLocals(&non_locals_);
165 Handle<Context> base_context = FindScriptOrNativeContext(outer_context);
166 Handle<Context> local_context =
135 it.HasContext() ? it.CurrentContext() : outer_context; 167 it.HasContext() ? it.CurrentContext() : outer_context;
136 168
137 // The "this" binding, if any, can't be bound via "with". If we need 169 // The "this" binding, if any, can't be bound via "with". If we need
138 // to, add another node onto the outer context to bind "this". 170 // to, add another node onto the outer context to bind "this".
139 parent_context = MaterializeReceiver(parent_context, function); 171 Handle<Context> receiver_context = MaterializeReceiver(
172 base_context, local_context, function, it.ThisIsNonLocal());
140 173
141 Handle<JSObject> materialized_function = NewJSObjectWithNullProto(); 174 Handle<JSObject> materialized_function = NewJSObjectWithNullProto();
142
143 frame_inspector.MaterializeStackLocals(materialized_function, function); 175 frame_inspector.MaterializeStackLocals(materialized_function, function);
144
145 MaterializeArgumentsObject(materialized_function, function); 176 MaterializeArgumentsObject(materialized_function, function);
177 MaterializeContextChain(materialized_function, local_context);
146 178
147 Handle<Context> with_context = isolate->factory()->NewWithContext( 179 Handle<Context> with_context = isolate->factory()->NewWithContext(
148 function, parent_context, materialized_function); 180 function, receiver_context, materialized_function);
149 181
150 ContextChainElement context_chain_element; 182 ContextChainElement context_chain_element;
151 context_chain_element.original_context = it.CurrentContext(); 183 context_chain_element.original_context = local_context;
152 context_chain_element.materialized_object = materialized_function; 184 context_chain_element.materialized_object = materialized_function;
153 context_chain_element.scope_info = it.CurrentScopeInfo(); 185 context_chain_element.scope_info = it.CurrentScopeInfo();
154 context_chain_.Add(context_chain_element); 186 context_chain_.Add(context_chain_element);
155 187
156 stop = true; 188 stop = true;
157 RecordContextsInChain(&inner_context, with_context, with_context); 189 RecordContextsInChain(&inner_context, receiver_context, with_context);
158 } else if (scope_type == ScopeIterator::ScopeTypeCatch || 190 } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
159 scope_type == ScopeIterator::ScopeTypeWith) { 191 scope_type == ScopeIterator::ScopeTypeWith) {
160 Handle<Context> cloned_context = Handle<Context>::cast( 192 Handle<Context> cloned_context = Handle<Context>::cast(
161 isolate->factory()->CopyFixedArray(it.CurrentContext())); 193 isolate->factory()->CopyFixedArray(it.CurrentContext()));
162 194
163 ContextChainElement context_chain_element; 195 ContextChainElement context_chain_element;
164 context_chain_element.original_context = it.CurrentContext(); 196 context_chain_element.original_context = it.CurrentContext();
165 context_chain_element.cloned_context = cloned_context; 197 context_chain_element.cloned_context = cloned_context;
166 context_chain_.Add(context_chain_element); 198 context_chain_.Add(context_chain_element);
167 199
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 } 232 }
201 } 233 }
202 if (innermost_context_.is_null()) { 234 if (innermost_context_.is_null()) {
203 innermost_context_ = outer_context; 235 innermost_context_ = outer_context;
204 } 236 }
205 DCHECK(!innermost_context_.is_null()); 237 DCHECK(!innermost_context_.is_null());
206 } 238 }
207 239
208 240
209 void DebugEvaluate::ContextBuilder::UpdateValues() { 241 void DebugEvaluate::ContextBuilder::UpdateValues() {
242 // TODO(yangguo): remove updating values.
210 for (int i = 0; i < context_chain_.length(); i++) { 243 for (int i = 0; i < context_chain_.length(); i++) {
211 ContextChainElement element = context_chain_[i]; 244 ContextChainElement element = context_chain_[i];
212 if (!element.original_context.is_null() && 245 if (!element.original_context.is_null() &&
213 !element.cloned_context.is_null()) { 246 !element.cloned_context.is_null()) {
214 Handle<Context> cloned_context = element.cloned_context; 247 Handle<Context> cloned_context = element.cloned_context;
215 cloned_context->CopyTo( 248 cloned_context->CopyTo(
216 Context::MIN_CONTEXT_SLOTS, *element.original_context, 249 Context::MIN_CONTEXT_SLOTS, *element.original_context,
217 Context::MIN_CONTEXT_SLOTS, 250 Context::MIN_CONTEXT_SLOTS,
218 cloned_context->length() - Context::MIN_CONTEXT_SLOTS); 251 cloned_context->length() - Context::MIN_CONTEXT_SLOTS);
219 } 252 }
220 if (!element.materialized_object.is_null()) { 253 if (!element.materialized_object.is_null()) {
221 // Write back potential changes to materialized stack locals to the 254 // Write back potential changes to materialized stack locals to the
222 // stack. 255 // stack.
223 FrameInspector(frame_, inlined_jsframe_index_, isolate_) 256 FrameInspector(frame_, inlined_jsframe_index_, isolate_)
224 .UpdateStackLocalsFromMaterializedObject(element.materialized_object, 257 .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
225 element.scope_info); 258 element.scope_info);
259 if (element.scope_info->scope_type() == FUNCTION_SCOPE) {
260 DCHECK_EQ(context_chain_.length() - 1, i);
261 UpdateContextChainFromMaterializedObject(element.materialized_object,
262 element.original_context);
263 }
226 } 264 }
227 } 265 }
228 } 266 }
229 267
230 268
231 Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() { 269 Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() {
232 Handle<JSObject> result = 270 Handle<JSObject> result =
233 isolate_->factory()->NewJSObject(isolate_->object_function()); 271 isolate_->factory()->NewJSObject(isolate_->object_function());
234 Handle<Map> new_map = 272 Handle<Map> new_map =
235 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); 273 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
(...skipping 28 matching lines...) Expand all
264 // FunctionGetArguments can't throw an exception. 302 // FunctionGetArguments can't throw an exception.
265 Handle<JSObject> arguments = 303 Handle<JSObject> arguments =
266 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function)); 304 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
267 Handle<String> arguments_str = isolate_->factory()->arguments_string(); 305 Handle<String> arguments_str = isolate_->factory()->arguments_string();
268 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments, 306 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
269 NONE) 307 NONE)
270 .Check(); 308 .Check();
271 } 309 }
272 310
273 311
312 MaybeHandle<Object> DebugEvaluate::ContextBuilder::LoadFromContext(
313 Handle<Context> context, Handle<String> name) {
314 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN;
315 int index;
316 PropertyAttributes attributes;
317 BindingFlags binding;
318 Handle<Object> holder =
319 context->Lookup(name, flags, &index, &attributes, &binding);
320 if (holder.is_null()) return MaybeHandle<Object>();
321 Handle<Object> value;
322 if (index != Context::kNotFound) { // Found on context.
323 Handle<Context> context = Handle<Context>::cast(holder);
324 return Handle<Object>(context->get(index), isolate_);
325 } else { // Found on object.
326 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
327 return JSReceiver::GetDataProperty(object, name);
328 }
329 }
330
331
332 void DebugEvaluate::ContextBuilder::MaterializeContextChain(
333 Handle<JSObject> target, Handle<Context> context) {
334 for (const Handle<String>& name : non_locals_) {
335 HandleScope scope(isolate_);
336 Handle<Object> value;
337 if (!LoadFromContext(context, name).ToHandle(&value)) continue;
338 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
339 }
340 }
341
342
343 void DebugEvaluate::ContextBuilder::StoreToContext(Handle<Context> context,
344 Handle<String> name,
345 Handle<Object> value) {
346 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN;
347 int index;
348 PropertyAttributes attributes;
349 BindingFlags binding;
350 Handle<Object> holder =
351 context->Lookup(name, flags, &index, &attributes, &binding);
352 if (holder.is_null()) return;
353 if (attributes & READ_ONLY) return;
354 if (index != Context::kNotFound) { // Found on context.
355 Handle<Context> context = Handle<Context>::cast(holder);
356 context->set(index, *value);
357 } else { // Found on object.
358 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
359 LookupIterator lookup(object, name);
360 if (lookup.state() != LookupIterator::DATA) return;
361 CHECK(JSReceiver::SetDataProperty(&lookup, value).FromJust());
362 }
363 }
364
365
366 void DebugEvaluate::ContextBuilder::UpdateContextChainFromMaterializedObject(
367 Handle<JSObject> source, Handle<Context> context) {
368 // TODO(yangguo): check whether overwriting context fields is actually safe
369 // wrt fields we consider constant.
370 for (const Handle<String>& name : non_locals_) {
371 HandleScope scope(isolate_);
372 Handle<Object> value = JSReceiver::GetDataProperty(source, name);
373 StoreToContext(context, name, value);
374 }
375 }
376
377
274 Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver( 378 Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver(
275 Handle<Context> target, Handle<JSFunction> function) { 379 Handle<Context> parent_context, Handle<Context> lookup_context,
276 Handle<SharedFunctionInfo> shared(function->shared()); 380 Handle<JSFunction> function, bool this_is_non_local) {
277 Handle<ScopeInfo> scope_info(shared->scope_info()); 381 Handle<Object> receiver = isolate_->factory()->undefined_value();
278 Handle<Object> receiver; 382 Handle<String> this_string = isolate_->factory()->this_string();
279 switch (scope_info->scope_type()) { 383 if (this_is_non_local) {
280 case FUNCTION_SCOPE: { 384 LoadFromContext(lookup_context, this_string).ToHandle(&receiver);
281 VariableMode mode; 385 } else if (function->shared()->scope_info()->HasReceiver()) {
282 InitializationFlag init_flag; 386 receiver = handle(frame_->receiver(), isolate_);
283 MaybeAssignedFlag maybe_assigned_flag;
284
285 // Don't bother creating a fake context node if "this" is in the context
286 // already.
287 if (ScopeInfo::ContextSlotIndex(scope_info,
288 isolate_->factory()->this_string(), &mode,
289 &init_flag, &maybe_assigned_flag) >= 0) {
290 return target;
291 }
292 receiver = handle(frame_->receiver(), isolate_);
293 break;
294 }
295 case MODULE_SCOPE:
296 receiver = isolate_->factory()->undefined_value();
297 break;
298 case SCRIPT_SCOPE:
299 receiver = handle(function->global_proxy(), isolate_);
300 break;
301 default:
302 // For eval code, arrow functions, and the like, there's no "this" binding
303 // to materialize.
304 return target;
305 } 387 }
306 388 return isolate_->factory()->NewCatchContext(function, parent_context,
307 return isolate_->factory()->NewCatchContext( 389 this_string, receiver);
308 function, target, isolate_->factory()->this_string(), receiver);
309 } 390 }
310 391
311 } // namespace internal 392 } // namespace internal
312 } // namespace v8 393 } // namespace v8
OLDNEW
« src/ast/scopes.cc ('K') | « src/debug/debug-evaluate.h ('k') | src/debug/debug-frames.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698