OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |