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

Side by Side Diff: src/deoptimizer.cc

Issue 11547015: Use a filter instead of a visitor to deoptimize selected functions in a context. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 #endif 240 #endif
241 241
242 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, 242 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
243 int count, 243 int count,
244 BailoutType type) { 244 BailoutType type) {
245 TableEntryGenerator generator(masm, type, count); 245 TableEntryGenerator generator(masm, type, count);
246 generator.Generate(); 246 generator.Generate();
247 } 247 }
248 248
249 249
250 class DeoptimizingVisitor : public OptimizedFunctionVisitor {
251 public:
252 virtual void EnterContext(Context* context) {
253 if (FLAG_trace_deopt) {
254 PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
255 reinterpret_cast<intptr_t>(context));
256 }
257 }
258
259 virtual void VisitFunction(JSFunction* function) {
260 Deoptimizer::DeoptimizeFunction(function);
261 }
262
263 virtual void LeaveContext(Context* context) {
264 context->ClearOptimizedFunctions();
265 }
266 };
267
268
269 void Deoptimizer::DeoptimizeAll() {
270 AssertNoAllocation no_allocation;
271
272 if (FLAG_trace_deopt) {
273 PrintF("[deoptimize all contexts]\n");
274 }
275
276 DeoptimizingVisitor visitor;
277 VisitAllOptimizedFunctions(&visitor);
278 }
279
280
281 void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
282 AssertNoAllocation no_allocation;
283
284 DeoptimizingVisitor visitor;
285 VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
286 }
287
288
289 void Deoptimizer::VisitAllOptimizedFunctionsForContext( 250 void Deoptimizer::VisitAllOptimizedFunctionsForContext(
290 Context* context, OptimizedFunctionVisitor* visitor) { 251 Context* context, OptimizedFunctionVisitor* visitor) {
291 Isolate* isolate = context->GetIsolate(); 252 Isolate* isolate = context->GetIsolate();
292 ZoneScope zone_scope(isolate->runtime_zone(), DELETE_ON_EXIT); 253 ZoneScope zone_scope(isolate->runtime_zone(), DELETE_ON_EXIT);
293 AssertNoAllocation no_allocation; 254 AssertNoAllocation no_allocation;
294 255
295 ASSERT(context->IsNativeContext()); 256 ASSERT(context->IsNativeContext());
296 257
297 visitor->EnterContext(context); 258 visitor->EnterContext(context);
298 259
299 // Create a snapshot of the optimized functions list. This is needed because 260 // Create a snapshot of the optimized functions list. This is needed because
300 // visitors might remove more than one link from the list at once. 261 // visitors might remove more than one link from the list at once.
301 ZoneList<JSFunction*> snapshot(1, isolate->runtime_zone()); 262 ZoneList<JSFunction*> snapshot(1, isolate->runtime_zone());
302 Object* element = context->OptimizedFunctionsListHead(); 263 Object* element = context->OptimizedFunctionsListHead();
303 while (!element->IsUndefined()) { 264 while (!element->IsUndefined()) {
304 JSFunction* element_function = JSFunction::cast(element); 265 JSFunction* element_function = JSFunction::cast(element);
305 snapshot.Add(element_function, isolate->runtime_zone()); 266 snapshot.Add(element_function, isolate->runtime_zone());
306 element = element_function->next_function_link(); 267 element = element_function->next_function_link();
307 } 268 }
308 269
309 // Run through the snapshot of optimized functions and visit them. 270 // Run through the snapshot of optimized functions and visit them.
310 for (int i = 0; i < snapshot.length(); ++i) { 271 for (int i = 0; i < snapshot.length(); ++i) {
311 visitor->VisitFunction(snapshot.at(i)); 272 visitor->VisitFunction(snapshot.at(i));
312 } 273 }
313 274
314 visitor->LeaveContext(context); 275 visitor->LeaveContext(context);
315 } 276 }
316 277
317 278
318 void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
319 JSObject* object, OptimizedFunctionVisitor* visitor) {
320 AssertNoAllocation no_allocation;
321
322 if (object->IsJSGlobalProxy()) {
323 Object* proto = object->GetPrototype();
324 ASSERT(proto->IsJSGlobalObject());
325 VisitAllOptimizedFunctionsForContext(
326 GlobalObject::cast(proto)->native_context(), visitor);
327 } else if (object->IsGlobalObject()) {
328 VisitAllOptimizedFunctionsForContext(
329 GlobalObject::cast(object)->native_context(), visitor);
330 }
331 }
332
333
334 void Deoptimizer::VisitAllOptimizedFunctions( 279 void Deoptimizer::VisitAllOptimizedFunctions(
335 OptimizedFunctionVisitor* visitor) { 280 OptimizedFunctionVisitor* visitor) {
336 AssertNoAllocation no_allocation; 281 AssertNoAllocation no_allocation;
337 282
338 // Run through the list of all native contexts and deoptimize. 283 // Run through the list of all native contexts and deoptimize.
339 Object* context = Isolate::Current()->heap()->native_contexts_list(); 284 Object* context = Isolate::Current()->heap()->native_contexts_list();
340 while (!context->IsUndefined()) { 285 while (!context->IsUndefined()) {
341 // GC can happen when the context is not fully initialized, 286 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
342 // so the global field of the context can be undefined.
343 Object* global = Context::cast(context)->get(Context::GLOBAL_OBJECT_INDEX);
344 if (!global->IsUndefined()) {
345 VisitAllOptimizedFunctionsForGlobalObject(JSObject::cast(global),
346 visitor);
347 }
348 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); 287 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
349 } 288 }
350 } 289 }
290
291
292 // Removes the functions selected by the given filter from the optimized
293 // function list of the given context and partitions the removed functions
294 // into one or more lists such that all functions in a list share the same
295 // code. The head of each list is written in the deoptimizing_functions field
296 // of the corresponding code object.
297 // The found code objects are returned in the given zone list.
298 static void PartitionOptimizedFunctions(Context* context,
299 OptimizedFunctionFilter* filter,
300 ZoneList<Code*>* partitions,
301 Zone* zone,
302 Object* undefined) {
303 AssertNoAllocation no_allocation;
304 Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST);
305 Object* remainder_head = undefined;
306 Object* remainder_tail = undefined;
307 ASSERT_EQ(0, partitions->length());
308 while (current != undefined) {
309 JSFunction* function = JSFunction::cast(current);
310 current = function->next_function_link();
311 if (filter->TakeFunction(function)) {
312 Code* code = function->code();
313 if (code->deoptimizing_functions() == undefined) {
314 partitions->Add(code, zone);
315 } else {
316 ASSERT(partitions->Contains(code));
317 }
318 function->set_next_function_link(code->deoptimizing_functions());
319 code->set_deoptimizing_functions(function);
320 } else {
321 if (remainder_head == undefined) {
322 remainder_head = function;
323 } else {
324 JSFunction::cast(remainder_tail)->set_next_function_link(function);
325 }
326 remainder_tail = function;
327 }
328 }
329 if (remainder_tail != undefined) {
330 JSFunction::cast(remainder_tail)->set_next_function_link(undefined);
331 }
332 context->set(Context::OPTIMIZED_FUNCTIONS_LIST, remainder_head);
333 }
334
335
336 class DeoptimizeAllFilter : public OptimizedFunctionFilter {
337 public:
338 virtual bool TakeFunction(JSFunction* function) {
339 return true;
340 }
341 };
342
343
344 class DeoptimizeWithMatchingCodeFilter : public OptimizedFunctionFilter {
345 public:
346 explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {}
347 virtual bool TakeFunction(JSFunction* function) {
348 return function->code() == code_;
349 }
350 private:
351 Code* code_;
352 };
353
354
355 void Deoptimizer::DeoptimizeAll() {
356 AssertNoAllocation no_allocation;
357
358 if (FLAG_trace_deopt) {
359 PrintF("[deoptimize all contexts]\n");
360 }
361
362 DeoptimizeAllFilter filter;
363 DeoptimizeAllFunctionsWith(&filter);
364 }
365
366
367 void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
368 AssertNoAllocation no_allocation;
369 DeoptimizeAllFilter filter;
370 if (object->IsJSGlobalProxy()) {
371 Object* proto = object->GetPrototype();
372 ASSERT(proto->IsJSGlobalObject());
373 DeoptimizeAllFunctionsForContext(
374 GlobalObject::cast(proto)->native_context(), &filter);
375 } else if (object->IsGlobalObject()) {
376 DeoptimizeAllFunctionsForContext(
377 GlobalObject::cast(object)->native_context(), &filter);
378 }
379 }
380
381
382 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
383 if (!function->IsOptimized()) return;
384 Code* code = function->code();
385 Context* context = function->context()->native_context();
386 Isolate* isolate = context->GetIsolate();
387 Object* undefined = isolate->heap()->undefined_value();
388 Zone* zone = isolate->runtime_zone();
389 ZoneScope zone_scope(zone, DELETE_ON_EXIT);
390 ZoneList<Code*> codes(1, zone);
391 DeoptimizeWithMatchingCodeFilter filter(code);
392 PartitionOptimizedFunctions(context, &filter, &codes, zone, undefined);
393 ASSERT_EQ(1, codes.length());
394 DeoptimizeFunctionWithPreparedFunctionList(
395 JSFunction::cast(codes.at(0)->deoptimizing_functions()));
396 codes.at(0)->set_deoptimizing_functions(undefined);
397 }
398
399
400 void Deoptimizer::DeoptimizeAllFunctionsForContext(
401 Context* context, OptimizedFunctionFilter* filter) {
402 ASSERT(context->IsNativeContext());
403 Isolate* isolate = context->GetIsolate();
404 Object* undefined = isolate->heap()->undefined_value();
405 Zone* zone = isolate->runtime_zone();
406 ZoneScope zone_scope(zone, DELETE_ON_EXIT);
407 ZoneList<Code*> codes(1, zone);
408 PartitionOptimizedFunctions(context, filter, &codes, zone, undefined);
409 for (int i = 0; i < codes.length(); ++i) {
410 DeoptimizeFunctionWithPreparedFunctionList(
411 JSFunction::cast(codes.at(i)->deoptimizing_functions()));
412 codes.at(i)->set_deoptimizing_functions(undefined);
413 }
414 }
415
416
417 void Deoptimizer::DeoptimizeAllFunctionsWith(OptimizedFunctionFilter* filter) {
418 AssertNoAllocation no_allocation;
419
420 // Run through the list of all native contexts and deoptimize.
421 Object* context = Isolate::Current()->heap()->native_contexts_list();
422 while (!context->IsUndefined()) {
423 DeoptimizeAllFunctionsForContext(Context::cast(context), filter);
424 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
425 }
426 }
351 427
352 428
353 void Deoptimizer::HandleWeakDeoptimizedCode( 429 void Deoptimizer::HandleWeakDeoptimizedCode(
354 v8::Persistent<v8::Value> obj, void* data) { 430 v8::Persistent<v8::Value> obj, void* data) {
355 DeoptimizingCodeListNode* node = 431 DeoptimizingCodeListNode* node =
356 reinterpret_cast<DeoptimizingCodeListNode*>(data); 432 reinterpret_cast<DeoptimizingCodeListNode*>(data);
357 RemoveDeoptimizingCode(*node->code()); 433 RemoveDeoptimizingCode(*node->code());
358 #ifdef DEBUG 434 #ifdef DEBUG
359 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_; 435 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
360 while (node != NULL) { 436 while (node != NULL) {
(...skipping 1108 matching lines...) Expand 10 before | Expand all | Expand 10 after
1469 // Move to next in list. 1545 // Move to next in list.
1470 prev = current; 1546 prev = current;
1471 current = current->next(); 1547 current = current->next();
1472 } 1548 }
1473 // Deoptimizing code is removed through weak callback. Each object is expected 1549 // Deoptimizing code is removed through weak callback. Each object is expected
1474 // to be removed once and only once. 1550 // to be removed once and only once.
1475 UNREACHABLE(); 1551 UNREACHABLE();
1476 } 1552 }
1477 1553
1478 1554
1479 static Object* CutOutRelatedFunctionsList(Context* context,
1480 Code* code,
1481 Object* undefined) {
1482 Object* result_list_head = undefined;
1483 Object* head;
1484 Object* current;
1485 current = head = context->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1486 JSFunction* prev = NULL;
1487 while (current != undefined) {
1488 JSFunction* func = JSFunction::cast(current);
1489 current = func->next_function_link();
1490 if (func->code() == code) {
1491 func->set_next_function_link(result_list_head);
1492 result_list_head = func;
1493 if (prev) {
1494 prev->set_next_function_link(current);
1495 } else {
1496 head = current;
1497 }
1498 } else {
1499 prev = func;
1500 }
1501 }
1502 if (head != context->get(Context::OPTIMIZED_FUNCTIONS_LIST)) {
1503 context->set(Context::OPTIMIZED_FUNCTIONS_LIST, head);
1504 }
1505 return result_list_head;
1506 }
1507
1508
1509 void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function, 1555 void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function,
1510 Code* code) { 1556 Code* code) {
1511 Context* context = function->context()->native_context();
1512
1513 SharedFunctionInfo* shared = function->shared(); 1557 SharedFunctionInfo* shared = function->shared();
1514
1515 Object* undefined = Isolate::Current()->heap()->undefined_value(); 1558 Object* undefined = Isolate::Current()->heap()->undefined_value();
1516 Object* current = CutOutRelatedFunctionsList(context, code, undefined); 1559 Object* current = function;
1517 1560
1518 while (current != undefined) { 1561 while (current != undefined) {
1519 JSFunction* func = JSFunction::cast(current); 1562 JSFunction* func = JSFunction::cast(current);
1520 current = func->next_function_link(); 1563 current = func->next_function_link();
1521 func->set_code(shared->code()); 1564 func->set_code(shared->code());
1522 func->set_next_function_link(undefined); 1565 func->set_next_function_link(undefined);
1523 } 1566 }
1524 } 1567 }
1525 1568
1526 1569
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after
2022 2065
2023 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { 2066 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
2024 v->VisitPointer(BitCast<Object**>(&function_)); 2067 v->VisitPointer(BitCast<Object**>(&function_));
2025 v->VisitPointers(parameters_, parameters_ + parameters_count_); 2068 v->VisitPointers(parameters_, parameters_ + parameters_count_);
2026 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); 2069 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
2027 } 2070 }
2028 2071
2029 #endif // ENABLE_DEBUGGER_SUPPORT 2072 #endif // ENABLE_DEBUGGER_SUPPORT
2030 2073
2031 } } // namespace v8::internal 2074 } } // namespace v8::internal
OLDNEW
« src/deoptimizer.h ('K') | « src/deoptimizer.h ('k') | src/ia32/deoptimizer-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698