| 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 |