OLD | NEW |
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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 | 66 |
67 // This is not a lot different than DebugEvaluate::Global, except that | 67 // This is not a lot different than DebugEvaluate::Global, except that |
68 // variables accessible by the function we are evaluating from are | 68 // variables accessible by the function we are evaluating from are |
69 // materialized and included on top of the native context. Changes to | 69 // materialized and included on top of the native context. Changes to |
70 // the materialized object are written back afterwards. | 70 // the materialized object are written back afterwards. |
71 // Note that the native context is taken from the original context chain, | 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. | 72 // which may not be the current native context of the isolate. |
73 ContextBuilder context_builder(isolate, frame, inlined_jsframe_index); | 73 ContextBuilder context_builder(isolate, frame, inlined_jsframe_index); |
74 if (isolate->has_pending_exception()) return MaybeHandle<Object>(); | 74 if (isolate->has_pending_exception()) return MaybeHandle<Object>(); |
75 | 75 |
76 Handle<Context> context = context_builder.native_context(); | 76 Handle<Context> context = context_builder.evaluation_context(); |
77 Handle<JSObject> receiver(context->global_proxy()); | 77 Handle<JSObject> receiver(context->global_proxy()); |
78 MaybeHandle<Object> maybe_result = Evaluate( | 78 MaybeHandle<Object> maybe_result = |
79 isolate, context_builder.outer_info(), | 79 Evaluate(isolate, context_builder.outer_info(), context, |
80 context_builder.innermost_context(), context_extension, receiver, source); | 80 context_extension, receiver, source); |
81 if (!maybe_result.is_null() && !FLAG_debug_eval_readonly_locals) { | 81 if (!maybe_result.is_null()) context_builder.UpdateValues(); |
82 context_builder.UpdateValues(); | |
83 } | |
84 return maybe_result; | 82 return maybe_result; |
85 } | 83 } |
86 | 84 |
87 | 85 |
88 // Compile and evaluate source for the given context. | 86 // Compile and evaluate source for the given context. |
89 MaybeHandle<Object> DebugEvaluate::Evaluate( | 87 MaybeHandle<Object> DebugEvaluate::Evaluate( |
90 Isolate* isolate, Handle<SharedFunctionInfo> outer_info, | 88 Isolate* isolate, Handle<SharedFunctionInfo> outer_info, |
91 Handle<Context> context, Handle<HeapObject> context_extension, | 89 Handle<Context> context, Handle<HeapObject> context_extension, |
92 Handle<Object> receiver, Handle<String> source) { | 90 Handle<Object> receiver, Handle<String> source) { |
93 if (context_extension->IsJSObject()) { | 91 if (context_extension->IsJSObject()) { |
(...skipping 29 matching lines...) Expand all Loading... |
123 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, | 121 DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, |
124 JavaScriptFrame* frame, | 122 JavaScriptFrame* frame, |
125 int inlined_jsframe_index) | 123 int inlined_jsframe_index) |
126 : isolate_(isolate), | 124 : isolate_(isolate), |
127 frame_(frame), | 125 frame_(frame), |
128 inlined_jsframe_index_(inlined_jsframe_index) { | 126 inlined_jsframe_index_(inlined_jsframe_index) { |
129 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | 127 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); |
130 Handle<JSFunction> local_function = | 128 Handle<JSFunction> local_function = |
131 Handle<JSFunction>::cast(frame_inspector.GetFunction()); | 129 Handle<JSFunction>::cast(frame_inspector.GetFunction()); |
132 Handle<Context> outer_context(local_function->context()); | 130 Handle<Context> outer_context(local_function->context()); |
133 native_context_ = Handle<Context>(outer_context->native_context()); | 131 evaluation_context_ = outer_context; |
134 Handle<JSFunction> global_function(native_context_->closure()); | 132 outer_info_ = handle(local_function->shared()); |
135 outer_info_ = handle(global_function->shared()); | 133 Factory* factory = isolate->factory(); |
136 Handle<Context> inner_context; | |
137 | 134 |
138 bool stop = false; | 135 // To evaluate as if we were running eval at the point of the debug break, |
139 | 136 // we reconstruct the context chain as follows: |
140 // Iterate the original context chain to create a context chain that reflects | 137 // - To make stack-allocated variables visible, we materialize them and |
141 // our needs. The original context chain may look like this: | 138 // use a debug-evaluate context to wrap both the materialized object and |
142 // <native context> <outer contexts> <function context> <inner contexts> | 139 // the original context. |
143 // In the resulting context chain, we want to materialize the receiver, | 140 // - We use the original context chain from the function context to the |
144 // the parameters of the current function, the stack locals. We only | 141 // native context. |
145 // materialize context variables that the function already references, | 142 // - Between the function scope and the native context, we only resolve |
146 // because only for those variables we can be sure that they will be resolved | 143 // variable names that the current function already uses. Only for these |
147 // correctly. Variables that are not referenced by the function may be | 144 // names we can be sure that they will be correctly resolved. For the |
148 // context-allocated and thus accessible, but may be shadowed by stack- | 145 // rest, we only resolve to with, script, and native contexts. We use a |
149 // allocated variables and the resolution would be incorrect. | 146 // whitelist to implement that. |
150 // The result will look like this: | 147 // Context::Lookup has special handling for debug-evaluate contexts: |
151 // <native context> <receiver context> | 148 // - Look up in the materialized stack variables. |
152 // <materialized stack and accessible context vars> <inner contexts> | 149 // - Look up in the original context. |
153 // All contexts use the closure of the native context, since there is no | 150 // - Check the whitelist to find out whether to skip contexts during lookup. |
154 // function context in the chain. Variables that cannot be resolved are | |
155 // bound to toplevel (script contexts or global object). | |
156 // Once debug-evaluate has been executed, the changes to the materialized | |
157 // objects are written back to the original context chain. Any changes to | |
158 // the original context chain will therefore be overwritten. | |
159 const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS; | 151 const ScopeIterator::Option option = ScopeIterator::COLLECT_NON_LOCALS; |
160 for (ScopeIterator it(isolate, &frame_inspector, option); | 152 for (ScopeIterator it(isolate, &frame_inspector, option); |
161 !it.Failed() && !it.Done() && !stop; it.Next()) { | 153 !it.Failed() && !it.Done(); it.Next()) { |
162 ScopeIterator::ScopeType scope_type = it.Type(); | 154 ScopeIterator::ScopeType scope_type = it.Type(); |
163 if (scope_type == ScopeIterator::ScopeTypeLocal) { | 155 if (scope_type == ScopeIterator::ScopeTypeLocal) { |
164 DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type()); | 156 DCHECK_EQ(FUNCTION_SCOPE, it.CurrentScopeInfo()->scope_type()); |
165 it.GetNonLocals(&non_locals_); | 157 Handle<JSObject> materialized = NewJSObjectWithNullProto(); |
166 Handle<Context> local_context = | 158 Handle<Context> local_context = |
167 it.HasContext() ? it.CurrentContext() : outer_context; | 159 it.HasContext() ? it.CurrentContext() : outer_context; |
168 | 160 MaterializeReceiver(materialized, local_context, local_function, |
169 // The "this" binding, if any, can't be bound via "with". If we need | 161 it.ThisIsNonLocal()); |
170 // to, add another node onto the outer context to bind "this". | 162 frame_inspector.MaterializeStackLocals(materialized, local_function); |
171 Handle<Context> receiver_context = | 163 MaterializeArgumentsObject(materialized, local_function); |
172 MaterializeReceiver(native_context_, local_context, local_function, | |
173 global_function, it.ThisIsNonLocal()); | |
174 | |
175 Handle<JSObject> materialized_function = NewJSObjectWithNullProto(); | |
176 frame_inspector.MaterializeStackLocals(materialized_function, | |
177 local_function); | |
178 MaterializeArgumentsObject(materialized_function, local_function); | |
179 MaterializeContextChain(materialized_function, local_context); | |
180 | |
181 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
182 global_function, receiver_context, materialized_function); | |
183 | |
184 ContextChainElement context_chain_element; | 164 ContextChainElement context_chain_element; |
185 context_chain_element.original_context = local_context; | |
186 context_chain_element.materialized_object = materialized_function; | |
187 context_chain_element.scope_info = it.CurrentScopeInfo(); | 165 context_chain_element.scope_info = it.CurrentScopeInfo(); |
| 166 context_chain_element.materialized_object = materialized; |
| 167 context_chain_element.whitelist = it.GetNonLocals(); |
| 168 if (it.HasContext()) { |
| 169 context_chain_element.wrapped_context = it.CurrentContext(); |
| 170 } |
188 context_chain_.Add(context_chain_element); | 171 context_chain_.Add(context_chain_element); |
189 | 172 evaluation_context_ = outer_context; |
190 stop = true; | 173 break; |
191 RecordContextsInChain(&inner_context, receiver_context, with_context); | |
192 } else if (scope_type == ScopeIterator::ScopeTypeCatch || | 174 } else if (scope_type == ScopeIterator::ScopeTypeCatch || |
193 scope_type == ScopeIterator::ScopeTypeWith) { | 175 scope_type == ScopeIterator::ScopeTypeWith) { |
194 Handle<Context> cloned_context = Handle<Context>::cast( | |
195 isolate->factory()->CopyFixedArray(it.CurrentContext())); | |
196 | |
197 ContextChainElement context_chain_element; | 176 ContextChainElement context_chain_element; |
198 context_chain_element.original_context = it.CurrentContext(); | 177 Handle<Context> current_context = it.CurrentContext(); |
199 context_chain_element.cloned_context = cloned_context; | 178 if (!current_context->IsDebugEvaluateContext()) { |
| 179 context_chain_element.wrapped_context = current_context; |
| 180 } |
200 context_chain_.Add(context_chain_element); | 181 context_chain_.Add(context_chain_element); |
201 | |
202 RecordContextsInChain(&inner_context, cloned_context, cloned_context); | |
203 } else if (scope_type == ScopeIterator::ScopeTypeBlock) { | 182 } else if (scope_type == ScopeIterator::ScopeTypeBlock) { |
204 Handle<JSObject> materialized_object = NewJSObjectWithNullProto(); | 183 Handle<JSObject> materialized = NewJSObjectWithNullProto(); |
205 frame_inspector.MaterializeStackLocals(materialized_object, | 184 frame_inspector.MaterializeStackLocals(materialized, |
206 it.CurrentScopeInfo()); | 185 it.CurrentScopeInfo()); |
| 186 ContextChainElement context_chain_element; |
| 187 context_chain_element.scope_info = it.CurrentScopeInfo(); |
| 188 context_chain_element.materialized_object = materialized; |
207 if (it.HasContext()) { | 189 if (it.HasContext()) { |
208 Handle<Context> cloned_context = Handle<Context>::cast( | 190 context_chain_element.wrapped_context = it.CurrentContext(); |
209 isolate->factory()->CopyFixedArray(it.CurrentContext())); | |
210 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
211 global_function, cloned_context, materialized_object); | |
212 | |
213 ContextChainElement context_chain_element; | |
214 context_chain_element.original_context = it.CurrentContext(); | |
215 context_chain_element.cloned_context = cloned_context; | |
216 context_chain_element.materialized_object = materialized_object; | |
217 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
218 context_chain_.Add(context_chain_element); | |
219 | |
220 RecordContextsInChain(&inner_context, cloned_context, with_context); | |
221 } else { | |
222 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
223 global_function, outer_context, materialized_object); | |
224 | |
225 ContextChainElement context_chain_element; | |
226 context_chain_element.materialized_object = materialized_object; | |
227 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
228 context_chain_.Add(context_chain_element); | |
229 | |
230 RecordContextsInChain(&inner_context, with_context, with_context); | |
231 } | 191 } |
| 192 context_chain_.Add(context_chain_element); |
232 } else { | 193 } else { |
233 stop = true; | 194 break; |
234 } | 195 } |
235 } | 196 } |
236 if (innermost_context_.is_null()) { | 197 |
237 innermost_context_ = outer_context; | 198 for (int i = context_chain_.length() - 1; i >= 0; i--) { |
| 199 evaluation_context_ = factory->NewDebugEvaluateContext( |
| 200 evaluation_context_, context_chain_[i].materialized_object, |
| 201 context_chain_[i].wrapped_context, context_chain_[i].whitelist); |
238 } | 202 } |
239 DCHECK(!innermost_context_.is_null()); | |
240 } | 203 } |
241 | 204 |
242 | 205 |
243 void DebugEvaluate::ContextBuilder::UpdateValues() { | 206 void DebugEvaluate::ContextBuilder::UpdateValues() { |
244 // TODO(yangguo): remove updating values. | 207 // TODO(yangguo): remove updating values. |
245 for (int i = 0; i < context_chain_.length(); i++) { | 208 for (int i = 0; i < context_chain_.length(); i++) { |
246 ContextChainElement element = context_chain_[i]; | 209 ContextChainElement element = context_chain_[i]; |
247 if (!element.original_context.is_null() && | |
248 !element.cloned_context.is_null()) { | |
249 Handle<Context> cloned_context = element.cloned_context; | |
250 cloned_context->CopyTo( | |
251 Context::MIN_CONTEXT_SLOTS, *element.original_context, | |
252 Context::MIN_CONTEXT_SLOTS, | |
253 cloned_context->length() - Context::MIN_CONTEXT_SLOTS); | |
254 } | |
255 if (!element.materialized_object.is_null()) { | 210 if (!element.materialized_object.is_null()) { |
256 // Write back potential changes to materialized stack locals to the | 211 // Write back potential changes to materialized stack locals to the stack. |
257 // stack. | |
258 FrameInspector(frame_, inlined_jsframe_index_, isolate_) | 212 FrameInspector(frame_, inlined_jsframe_index_, isolate_) |
259 .UpdateStackLocalsFromMaterializedObject(element.materialized_object, | 213 .UpdateStackLocalsFromMaterializedObject(element.materialized_object, |
260 element.scope_info); | 214 element.scope_info); |
261 if (element.scope_info->scope_type() == FUNCTION_SCOPE) { | |
262 DCHECK_EQ(context_chain_.length() - 1, i); | |
263 UpdateContextChainFromMaterializedObject(element.materialized_object, | |
264 element.original_context); | |
265 } | |
266 } | 215 } |
267 } | 216 } |
268 } | 217 } |
269 | 218 |
270 | 219 |
271 Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() { | 220 Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() { |
272 Handle<JSObject> result = | 221 Handle<JSObject> result = |
273 isolate_->factory()->NewJSObject(isolate_->object_function()); | 222 isolate_->factory()->NewJSObject(isolate_->object_function()); |
274 Handle<Map> new_map = | 223 Handle<Map> new_map = |
275 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); | 224 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); |
276 Map::SetPrototype(new_map, isolate_->factory()->null_value()); | 225 Map::SetPrototype(new_map, isolate_->factory()->null_value()); |
277 JSObject::MigrateToMap(result, new_map); | 226 JSObject::MigrateToMap(result, new_map); |
278 return result; | 227 return result; |
279 } | 228 } |
280 | 229 |
281 | 230 |
282 void DebugEvaluate::ContextBuilder::RecordContextsInChain( | |
283 Handle<Context>* inner_context, Handle<Context> first, | |
284 Handle<Context> last) { | |
285 if (!inner_context->is_null()) { | |
286 (*inner_context)->set_previous(*last); | |
287 } else { | |
288 innermost_context_ = last; | |
289 } | |
290 *inner_context = first; | |
291 } | |
292 | |
293 | |
294 void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject( | 231 void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject( |
295 Handle<JSObject> target, Handle<JSFunction> function) { | 232 Handle<JSObject> target, Handle<JSFunction> function) { |
296 // Do not materialize the arguments object for eval or top-level code. | 233 // Do not materialize the arguments object for eval or top-level code. |
297 // Skip if "arguments" is already taken. | 234 // Skip if "arguments" is already taken. |
298 if (!function->shared()->is_function()) return; | 235 if (!function->shared()->is_function()) return; |
299 Maybe<bool> maybe = JSReceiver::HasOwnProperty( | 236 Maybe<bool> maybe = JSReceiver::HasOwnProperty( |
300 target, isolate_->factory()->arguments_string()); | 237 target, isolate_->factory()->arguments_string()); |
301 DCHECK(maybe.IsJust()); | 238 DCHECK(maybe.IsJust()); |
302 if (maybe.FromJust()) return; | 239 if (maybe.FromJust()) return; |
303 | 240 |
304 // FunctionGetArguments can't throw an exception. | 241 // FunctionGetArguments can't throw an exception. |
305 Handle<JSObject> arguments = Accessors::FunctionGetArguments(function); | 242 Handle<JSObject> arguments = Accessors::FunctionGetArguments(function); |
306 Handle<String> arguments_str = isolate_->factory()->arguments_string(); | 243 Handle<String> arguments_str = isolate_->factory()->arguments_string(); |
307 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments, | 244 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments, |
308 NONE) | 245 NONE) |
309 .Check(); | 246 .Check(); |
310 } | 247 } |
311 | 248 |
312 | 249 void DebugEvaluate::ContextBuilder::MaterializeReceiver( |
313 MaybeHandle<Object> DebugEvaluate::ContextBuilder::LoadFromContext( | 250 Handle<JSObject> target, Handle<Context> local_context, |
314 Handle<Context> context, Handle<String> name, bool* global) { | 251 Handle<JSFunction> local_function, bool this_is_non_local) { |
315 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN; | 252 Handle<Object> recv = isolate_->factory()->undefined_value(); |
316 int index; | 253 Handle<String> name = isolate_->factory()->this_string(); |
317 PropertyAttributes attributes; | 254 if (this_is_non_local) { |
318 BindingFlags binding; | 255 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN; |
319 Handle<Object> holder = | 256 int index; |
320 context->Lookup(name, flags, &index, &attributes, &binding); | 257 PropertyAttributes attributes; |
321 if (holder.is_null()) return MaybeHandle<Object>(); | 258 BindingFlags binding; |
322 Handle<Object> value; | 259 Handle<Object> holder = |
323 if (index != Context::kNotFound) { // Found on context. | 260 local_context->Lookup(name, flags, &index, &attributes, &binding); |
324 Handle<Context> context = Handle<Context>::cast(holder); | 261 if (!holder.is_null() && index != Context::kNotFound) { |
325 // Do not shadow variables on the script context. | 262 // Found on context. |
326 *global = context->IsScriptContext(); | 263 Handle<Context> context = Handle<Context>::cast(holder); |
327 return Handle<Object>(context->get(index), isolate_); | 264 recv = Handle<Object>(context->get(index), isolate_); |
328 } else { // Found on object. | 265 } |
329 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); | 266 } else if (local_function->shared()->scope_info()->HasReceiver()) { |
330 // Do not shadow properties on the global object. | 267 recv = handle(frame_->receiver(), isolate_); |
331 *global = object->IsJSGlobalObject(); | |
332 return JSReceiver::GetDataProperty(object, name); | |
333 } | 268 } |
334 } | 269 JSObject::SetOwnPropertyIgnoreAttributes(target, name, recv, NONE).Check(); |
335 | |
336 | |
337 void DebugEvaluate::ContextBuilder::MaterializeContextChain( | |
338 Handle<JSObject> target, Handle<Context> context) { | |
339 for (const Handle<String>& name : non_locals_) { | |
340 HandleScope scope(isolate_); | |
341 Handle<Object> value; | |
342 bool global; | |
343 if (!LoadFromContext(context, name, &global).ToHandle(&value) || global) { | |
344 // If resolving the variable fails, skip it. If it resolves to a global | |
345 // variable, skip it as well since it's not read-only and can be resolved | |
346 // within debug-evaluate. | |
347 continue; | |
348 } | |
349 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check(); | |
350 } | |
351 } | |
352 | |
353 | |
354 void DebugEvaluate::ContextBuilder::StoreToContext(Handle<Context> context, | |
355 Handle<String> name, | |
356 Handle<Object> value) { | |
357 static const ContextLookupFlags flags = FOLLOW_CONTEXT_CHAIN; | |
358 int index; | |
359 PropertyAttributes attributes; | |
360 BindingFlags binding; | |
361 Handle<Object> holder = | |
362 context->Lookup(name, flags, &index, &attributes, &binding); | |
363 if (holder.is_null()) return; | |
364 if (attributes & READ_ONLY) return; | |
365 if (index != Context::kNotFound) { // Found on context. | |
366 Handle<Context> context = Handle<Context>::cast(holder); | |
367 context->set(index, *value); | |
368 } else { // Found on object. | |
369 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); | |
370 LookupIterator lookup(object, name); | |
371 if (lookup.state() != LookupIterator::DATA) return; | |
372 CHECK(JSReceiver::SetDataProperty(&lookup, value).FromJust()); | |
373 } | |
374 } | |
375 | |
376 | |
377 void DebugEvaluate::ContextBuilder::UpdateContextChainFromMaterializedObject( | |
378 Handle<JSObject> source, Handle<Context> context) { | |
379 // TODO(yangguo): check whether overwriting context fields is actually safe | |
380 // wrt fields we consider constant. | |
381 for (const Handle<String>& name : non_locals_) { | |
382 HandleScope scope(isolate_); | |
383 Handle<Object> value = JSReceiver::GetDataProperty(source, name); | |
384 StoreToContext(context, name, value); | |
385 } | |
386 } | |
387 | |
388 | |
389 Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver( | |
390 Handle<Context> parent_context, Handle<Context> lookup_context, | |
391 Handle<JSFunction> local_function, Handle<JSFunction> global_function, | |
392 bool this_is_non_local) { | |
393 Handle<Object> receiver = isolate_->factory()->undefined_value(); | |
394 Handle<String> this_string = isolate_->factory()->this_string(); | |
395 if (this_is_non_local) { | |
396 bool global; | |
397 LoadFromContext(lookup_context, this_string, &global).ToHandle(&receiver); | |
398 } else if (local_function->shared()->scope_info()->HasReceiver()) { | |
399 receiver = handle(frame_->receiver(), isolate_); | |
400 } | |
401 return isolate_->factory()->NewCatchContext(global_function, parent_context, | |
402 this_string, receiver); | |
403 } | 270 } |
404 | 271 |
405 } // namespace internal | 272 } // namespace internal |
406 } // namespace v8 | 273 } // namespace v8 |
OLD | NEW |