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

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: add TODO 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 JavaScriptFrameIterator it(isolate, frame_id); 57 JavaScriptFrameIterator it(isolate, frame_id);
58 JavaScriptFrame* frame = it.frame(); 58 JavaScriptFrame* frame = it.frame();
59 59
60 // Traverse the saved contexts chain to find the active context for the 60 // Traverse the saved contexts chain to find the active context for the
61 // selected frame. 61 // selected frame.
62 SaveContext* save = 62 SaveContext* save =
63 DebugFrameHelper::FindSavedContextForFrame(isolate, frame); 63 DebugFrameHelper::FindSavedContextForFrame(isolate, frame);
64 SaveContext savex(isolate); 64 SaveContext savex(isolate);
65 isolate->set_context(*(save->context())); 65 isolate->set_context(*(save->context()));
66 66
67 // Materialize stack locals and the arguments object. 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.
68 ContextBuilder context_builder(isolate, frame, inlined_jsframe_index); 71 ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
69 if (isolate->has_pending_exception()) return MaybeHandle<Object>(); 72 if (isolate->has_pending_exception()) return MaybeHandle<Object>();
70 73
71 Handle<Object> receiver(frame->receiver(), isolate); 74 Handle<Context> context = isolate->native_context();
75 Handle<JSObject> receiver(context->global_proxy());
76 Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
72 MaybeHandle<Object> maybe_result = Evaluate( 77 MaybeHandle<Object> maybe_result = Evaluate(
73 isolate, context_builder.outer_info(), 78 isolate, context_builder.outer_info(),
74 context_builder.innermost_context(), context_extension, receiver, source); 79 context_builder.innermost_context(), context_extension, receiver, source);
75 if (!maybe_result.is_null()) context_builder.UpdateValues(); 80 if (!maybe_result.is_null()) context_builder.UpdateValues();
76 return maybe_result; 81 return maybe_result;
77 } 82 }
78 83
79 84
80 // Compile and evaluate source for the given context. 85 // Compile and evaluate source for the given context.
81 MaybeHandle<Object> DebugEvaluate::Evaluate( 86 MaybeHandle<Object> DebugEvaluate::Evaluate(
(...skipping 30 matching lines...) Expand all
112 } 117 }
113 118
114 119
115 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, 120 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
116 JavaScriptFrame* frame, 121 JavaScriptFrame* frame,
117 int inlined_jsframe_index) 122 int inlined_jsframe_index)
118 : isolate_(isolate), 123 : isolate_(isolate),
119 frame_(frame), 124 frame_(frame),
120 inlined_jsframe_index_(inlined_jsframe_index) { 125 inlined_jsframe_index_(inlined_jsframe_index) {
121 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 126 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
122 Handle<JSFunction> function = 127 Handle<JSFunction> local_function =
123 handle(JSFunction::cast(frame_inspector.GetFunction())); 128 handle(JSFunction::cast(frame_inspector.GetFunction()));
124 Handle<Context> outer_context = handle(function->context(), isolate); 129 Handle<Context> outer_context(local_function->context());
125 outer_info_ = handle(function->shared()); 130 Handle<Context> native_context = isolate->native_context();
131 Handle<JSFunction> global_function(native_context->closure());
132 outer_info_ = handle(global_function->shared());
126 Handle<Context> inner_context; 133 Handle<Context> inner_context;
127 134
128 bool stop = false; 135 bool stop = false;
129 for (ScopeIterator it(isolate, &frame_inspector); 136
137 // Iterate the original context chain to create a context chain that reflects
138 // our needs. The original context chain may look like this:
139 // <native context> <outer contexts> <function context> <inner contexts>
140 // In the resulting context chain, we want to materialize the receiver,
141 // the parameters of the current function, the stack locals. We only
142 // materialize context variables that the function already references,
143 // because only for those variables we can be sure that they will be resolved
144 // correctly. Variables that are not referenced by the function may be
145 // context-allocated and thus accessible, but may be shadowed by stack-
146 // allocated variables and the resolution would be incorrect.
147 // The result will look like this:
148 // <native context> <receiver context>
149 // <materialized stack and accessible context vars> <inner contexts>
150 // All contexts use the closure of the native context, since there is no
151 // function context in the chain. Variables that cannot be resolved are
152 // bound to toplevel (script contexts or global object).
153 // Once debug-evaluate has been executed, the changes to the materialized
154 // objects are written back to the original context chain. Any changes to
155 // the original context chain will therefore be overwritten.
156 const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS;
157 for (ScopeIterator it(isolate, &frame_inspector, option);
130 !it.Failed() && !it.Done() && !stop; it.Next()) { 158 !it.Failed() && !it.Done() && !stop; it.Next()) {
131 ScopeIterator::ScopeType scope_type = it.Type(); 159 ScopeIterator::ScopeType scope_type = it.Type();
132
133 if (scope_type == ScopeIterator::ScopeTypeLocal) { 160 if (scope_type == ScopeIterator::ScopeTypeLocal) {
134 Handle<Context> parent_context = 161 DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type());
162 it.GetNonLocals(&non_locals_);
163 Handle<Context> local_context =
135 it.HasContext() ? it.CurrentContext() : outer_context; 164 it.HasContext() ? it.CurrentContext() : outer_context;
136 165
137 // The "this" binding, if any, can't be bound via "with". If we need 166 // 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". 167 // to, add another node onto the outer context to bind "this".
139 parent_context = MaterializeReceiver(parent_context, function); 168 Handle<Context> receiver_context =
169 MaterializeReceiver(native_context, local_context, local_function,
170 global_function, it.ThisIsNonLocal());
140 171
141 Handle<JSObject> materialized_function = NewJSObjectWithNullProto(); 172 Handle<JSObject> materialized_function = NewJSObjectWithNullProto();
142 173 frame_inspector.MaterializeStackLocals(materialized_function,
143 frame_inspector.MaterializeStackLocals(materialized_function, function); 174 local_function);
144 175 MaterializeArgumentsObject(materialized_function, local_function);
145 MaterializeArgumentsObject(materialized_function, function); 176 MaterializeContextChain(materialized_function, local_context);
146 177
147 Handle<Context> with_context = isolate->factory()->NewWithContext( 178 Handle<Context> with_context = isolate->factory()->NewWithContext(
148 function, parent_context, materialized_function); 179 global_function, receiver_context, materialized_function);
149 180
150 ContextChainElement context_chain_element; 181 ContextChainElement context_chain_element;
151 context_chain_element.original_context = it.CurrentContext(); 182 context_chain_element.original_context = local_context;
152 context_chain_element.materialized_object = materialized_function; 183 context_chain_element.materialized_object = materialized_function;
153 context_chain_element.scope_info = it.CurrentScopeInfo(); 184 context_chain_element.scope_info = it.CurrentScopeInfo();
154 context_chain_.Add(context_chain_element); 185 context_chain_.Add(context_chain_element);
155 186
156 stop = true; 187 stop = true;
157 RecordContextsInChain(&inner_context, with_context, with_context); 188 RecordContextsInChain(&inner_context, receiver_context, with_context);
158 } else if (scope_type == ScopeIterator::ScopeTypeCatch || 189 } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
159 scope_type == ScopeIterator::ScopeTypeWith) { 190 scope_type == ScopeIterator::ScopeTypeWith) {
160 Handle<Context> cloned_context = Handle<Context>::cast( 191 Handle<Context> cloned_context = Handle<Context>::cast(
161 isolate->factory()->CopyFixedArray(it.CurrentContext())); 192 isolate->factory()->CopyFixedArray(it.CurrentContext()));
162 193
163 ContextChainElement context_chain_element; 194 ContextChainElement context_chain_element;
164 context_chain_element.original_context = it.CurrentContext(); 195 context_chain_element.original_context = it.CurrentContext();
165 context_chain_element.cloned_context = cloned_context; 196 context_chain_element.cloned_context = cloned_context;
166 context_chain_.Add(context_chain_element); 197 context_chain_.Add(context_chain_element);
167 198
168 RecordContextsInChain(&inner_context, cloned_context, cloned_context); 199 RecordContextsInChain(&inner_context, cloned_context, cloned_context);
169 } else if (scope_type == ScopeIterator::ScopeTypeBlock) { 200 } else if (scope_type == ScopeIterator::ScopeTypeBlock) {
170 Handle<JSObject> materialized_object = NewJSObjectWithNullProto(); 201 Handle<JSObject> materialized_object = NewJSObjectWithNullProto();
171 frame_inspector.MaterializeStackLocals(materialized_object, 202 frame_inspector.MaterializeStackLocals(materialized_object,
172 it.CurrentScopeInfo()); 203 it.CurrentScopeInfo());
173 if (it.HasContext()) { 204 if (it.HasContext()) {
174 Handle<Context> cloned_context = Handle<Context>::cast( 205 Handle<Context> cloned_context = Handle<Context>::cast(
175 isolate->factory()->CopyFixedArray(it.CurrentContext())); 206 isolate->factory()->CopyFixedArray(it.CurrentContext()));
176 Handle<Context> with_context = isolate->factory()->NewWithContext( 207 Handle<Context> with_context = isolate->factory()->NewWithContext(
177 function, cloned_context, materialized_object); 208 global_function, cloned_context, materialized_object);
178 209
179 ContextChainElement context_chain_element; 210 ContextChainElement context_chain_element;
180 context_chain_element.original_context = it.CurrentContext(); 211 context_chain_element.original_context = it.CurrentContext();
181 context_chain_element.cloned_context = cloned_context; 212 context_chain_element.cloned_context = cloned_context;
182 context_chain_element.materialized_object = materialized_object; 213 context_chain_element.materialized_object = materialized_object;
183 context_chain_element.scope_info = it.CurrentScopeInfo(); 214 context_chain_element.scope_info = it.CurrentScopeInfo();
184 context_chain_.Add(context_chain_element); 215 context_chain_.Add(context_chain_element);
185 216
186 RecordContextsInChain(&inner_context, cloned_context, with_context); 217 RecordContextsInChain(&inner_context, cloned_context, with_context);
187 } else { 218 } else {
188 Handle<Context> with_context = isolate->factory()->NewWithContext( 219 Handle<Context> with_context = isolate->factory()->NewWithContext(
189 function, outer_context, materialized_object); 220 global_function, outer_context, materialized_object);
190 221
191 ContextChainElement context_chain_element; 222 ContextChainElement context_chain_element;
192 context_chain_element.materialized_object = materialized_object; 223 context_chain_element.materialized_object = materialized_object;
193 context_chain_element.scope_info = it.CurrentScopeInfo(); 224 context_chain_element.scope_info = it.CurrentScopeInfo();
194 context_chain_.Add(context_chain_element); 225 context_chain_.Add(context_chain_element);
195 226
196 RecordContextsInChain(&inner_context, with_context, with_context); 227 RecordContextsInChain(&inner_context, with_context, with_context);
197 } 228 }
198 } else { 229 } else {
199 stop = true; 230 stop = true;
200 } 231 }
201 } 232 }
202 if (innermost_context_.is_null()) { 233 if (innermost_context_.is_null()) {
203 innermost_context_ = outer_context; 234 innermost_context_ = outer_context;
204 } 235 }
205 DCHECK(!innermost_context_.is_null()); 236 DCHECK(!innermost_context_.is_null());
206 } 237 }
207 238
208 239
209 void DebugEvaluate::ContextBuilder::UpdateValues() { 240 void DebugEvaluate::ContextBuilder::UpdateValues() {
241 // TODO(yangguo): remove updating values.
210 for (int i = 0; i < context_chain_.length(); i++) { 242 for (int i = 0; i < context_chain_.length(); i++) {
211 ContextChainElement element = context_chain_[i]; 243 ContextChainElement element = context_chain_[i];
212 if (!element.original_context.is_null() && 244 if (!element.original_context.is_null() &&
213 !element.cloned_context.is_null()) { 245 !element.cloned_context.is_null()) {
214 Handle<Context> cloned_context = element.cloned_context; 246 Handle<Context> cloned_context = element.cloned_context;
215 cloned_context->CopyTo( 247 cloned_context->CopyTo(
216 Context::MIN_CONTEXT_SLOTS, *element.original_context, 248 Context::MIN_CONTEXT_SLOTS, *element.original_context,
217 Context::MIN_CONTEXT_SLOTS, 249 Context::MIN_CONTEXT_SLOTS,
218 cloned_context->length() - Context::MIN_CONTEXT_SLOTS); 250 cloned_context->length() - Context::MIN_CONTEXT_SLOTS);
219 } 251 }
220 if (!element.materialized_object.is_null()) { 252 if (!element.materialized_object.is_null()) {
221 // Write back potential changes to materialized stack locals to the 253 // Write back potential changes to materialized stack locals to the
222 // stack. 254 // stack.
223 FrameInspector(frame_, inlined_jsframe_index_, isolate_) 255 FrameInspector(frame_, inlined_jsframe_index_, isolate_)
224 .UpdateStackLocalsFromMaterializedObject(element.materialized_object, 256 .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
225 element.scope_info); 257 element.scope_info);
258 if (element.scope_info->scope_type() == FUNCTION_SCOPE) {
259 DCHECK_EQ(context_chain_.length() - 1, i);
260 UpdateContextChainFromMaterializedObject(element.materialized_object,
261 element.original_context);
262 }
226 } 263 }
227 } 264 }
228 } 265 }
229 266
230 267
231 Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() { 268 Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() {
232 Handle<JSObject> result = 269 Handle<JSObject> result =
233 isolate_->factory()->NewJSObject(isolate_->object_function()); 270 isolate_->factory()->NewJSObject(isolate_->object_function());
234 Handle<Map> new_map = 271 Handle<Map> new_map =
235 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); 272 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
(...skipping 28 matching lines...) Expand all
264 // FunctionGetArguments can't throw an exception. 301 // FunctionGetArguments can't throw an exception.
265 Handle<JSObject> arguments = 302 Handle<JSObject> arguments =
266 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function)); 303 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
267 Handle<String> arguments_str = isolate_->factory()->arguments_string(); 304 Handle<String> arguments_str = isolate_->factory()->arguments_string();
268 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments, 305 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
269 NONE) 306 NONE)
270 .Check(); 307 .Check();
271 } 308 }
272 309
273 310
311 MaybeHandle<Object> DebugEvaluate::ContextBuilder::LoadFromContext(
312 Handle<Context> context, Handle<String> name) {
313 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN;
314 int index;
315 PropertyAttributes attributes;
316 BindingFlags binding;
317 Handle<Object> holder =
318 context->Lookup(name, flags, &index, &attributes, &binding);
319 if (holder.is_null()) return MaybeHandle<Object>();
320 Handle<Object> value;
321 if (index != Context::kNotFound) { // Found on context.
322 Handle<Context> context = Handle<Context>::cast(holder);
323 return Handle<Object>(context->get(index), isolate_);
324 } else { // Found on object.
325 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
326 return JSReceiver::GetDataProperty(object, name);
327 }
328 }
329
330
331 void DebugEvaluate::ContextBuilder::MaterializeContextChain(
332 Handle<JSObject> target, Handle<Context> context) {
333 for (const Handle<String>& name : non_locals_) {
334 HandleScope scope(isolate_);
335 Handle<Object> value;
336 if (!LoadFromContext(context, name).ToHandle(&value)) continue;
337 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
338 }
339 }
340
341
342 void DebugEvaluate::ContextBuilder::StoreToContext(Handle<Context> context,
343 Handle<String> name,
344 Handle<Object> value) {
345 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN;
346 int index;
347 PropertyAttributes attributes;
348 BindingFlags binding;
349 Handle<Object> holder =
350 context->Lookup(name, flags, &index, &attributes, &binding);
351 if (holder.is_null()) return;
352 if (attributes & READ_ONLY) return;
353 if (index != Context::kNotFound) { // Found on context.
354 Handle<Context> context = Handle<Context>::cast(holder);
355 context->set(index, *value);
356 } else { // Found on object.
357 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
358 LookupIterator lookup(object, name);
359 if (lookup.state() != LookupIterator::DATA) return;
360 CHECK(JSReceiver::SetDataProperty(&lookup, value).FromJust());
361 }
362 }
363
364
365 void DebugEvaluate::ContextBuilder::UpdateContextChainFromMaterializedObject(
366 Handle<JSObject> source, Handle<Context> context) {
367 // TODO(yangguo): check whether overwriting context fields is actually safe
368 // wrt fields we consider constant.
369 for (const Handle<String>& name : non_locals_) {
370 HandleScope scope(isolate_);
371 Handle<Object> value = JSReceiver::GetDataProperty(source, name);
372 StoreToContext(context, name, value);
373 }
374 }
375
376
274 Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver( 377 Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver(
275 Handle<Context> target, Handle<JSFunction> function) { 378 Handle<Context> parent_context, Handle<Context> lookup_context,
276 Handle<SharedFunctionInfo> shared(function->shared()); 379 Handle<JSFunction> local_function, Handle<JSFunction> global_function,
277 Handle<ScopeInfo> scope_info(shared->scope_info()); 380 bool this_is_non_local) {
278 Handle<Object> receiver; 381 Handle<Object> receiver = isolate_->factory()->undefined_value();
279 switch (scope_info->scope_type()) { 382 Handle<String> this_string = isolate_->factory()->this_string();
280 case FUNCTION_SCOPE: { 383 if (this_is_non_local) {
281 VariableMode mode; 384 LoadFromContext(lookup_context, this_string).ToHandle(&receiver);
282 InitializationFlag init_flag; 385 } else if (local_function->shared()->scope_info()->HasReceiver()) {
283 MaybeAssignedFlag maybe_assigned_flag; 386 receiver = handle(frame_->receiver(), isolate_);
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(global_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.h ('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