| 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 2353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2364 StrictModeFlag strict_mode = ic.strict_mode(); | 2364 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2365 return Runtime::SetObjectProperty(isolate, | 2365 return Runtime::SetObjectProperty(isolate, |
| 2366 object, | 2366 object, |
| 2367 key, | 2367 key, |
| 2368 value, | 2368 value, |
| 2369 NONE, | 2369 NONE, |
| 2370 strict_mode); | 2370 strict_mode); |
| 2371 } | 2371 } |
| 2372 | 2372 |
| 2373 | 2373 |
| 2374 void BinaryOpIC::patch(Code* code) { | |
| 2375 set_target(code); | |
| 2376 } | |
| 2377 | |
| 2378 | |
| 2379 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2374 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 2380 switch (type_info) { | 2375 switch (type_info) { |
| 2381 case UNINITIALIZED: return "Uninitialized"; | 2376 case UNINITIALIZED: return "Uninitialized"; |
| 2382 case SMI: return "Smi"; | 2377 case SMI: return "Smi"; |
| 2383 case INT32: return "Int32"; | 2378 case INT32: return "Int32"; |
| 2384 case NUMBER: return "Number"; | 2379 case NUMBER: return "Number"; |
| 2385 case ODDBALL: return "Oddball"; | 2380 case ODDBALL: return "Oddball"; |
| 2386 case STRING: return "String"; | 2381 case STRING: return "String"; |
| 2387 case GENERIC: return "Generic"; | 2382 case GENERIC: return "Generic"; |
| 2388 default: return "Invalid"; | 2383 default: return "Invalid"; |
| 2389 } | 2384 } |
| 2390 } | 2385 } |
| 2391 | 2386 |
| 2392 | 2387 |
| 2393 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2388 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2394 switch (type_info) { | 2389 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2395 case UNINITIALIZED: | 2390 BinaryOpStub stub(extra_ic_state); |
| 2396 return ::v8::internal::UNINITIALIZED; | 2391 |
| 2397 case SMI: | 2392 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2398 case INT32: | 2393 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2399 case NUMBER: | 2394 |
| 2400 case ODDBALL: | 2395 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
| 2401 case STRING: | 2396 |
| 2402 return MONOMORPHIC; | 2397 #ifdef DEBUG |
| 2403 case GENERIC: | 2398 if (FLAG_trace_ic) { |
| 2404 return ::v8::internal::GENERIC; | 2399 char buffer[100]; |
| 2400 NoAllocationStringAllocator allocator(buffer, |
| 2401 static_cast<unsigned>(sizeof(buffer))); |
| 2402 StringStream stream(&allocator); |
| 2403 stream.Add("["); |
| 2404 stub.PrintName(&stream); |
| 2405 |
| 2406 stub.UpdateStatus(left, right, result); |
| 2407 |
| 2408 stream.Add(" => "); |
| 2409 stub.PrintState(&stream); |
| 2410 stream.Add(" "); |
| 2411 stream.OutputToStdOut(); |
| 2412 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2413 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2414 PrintF("]\n"); |
| 2415 } else { |
| 2416 stub.UpdateStatus(left, right, result); |
| 2405 } | 2417 } |
| 2406 UNREACHABLE(); | 2418 #else |
| 2407 return ::v8::internal::UNINITIALIZED; | 2419 stub.UpdateStatus(left, right, result); |
| 2420 #endif |
| 2421 |
| 2422 Handle<Code> code = stub.GetCode(isolate()); |
| 2423 set_target(*code); |
| 2424 |
| 2425 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2426 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2427 |
| 2428 if (!smi_was_enabled && enable_smi) { |
| 2429 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2430 } else if (smi_was_enabled && !enable_smi) { |
| 2431 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2432 } |
| 2433 |
| 2434 return result.has_value |
| 2435 ? static_cast<MaybeObject*>(*result.value) |
| 2436 : Failure::Exception(); |
| 2408 } | 2437 } |
| 2409 | 2438 |
| 2410 | 2439 |
| 2411 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2440 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2412 Isolate* isolate) { | 2441 HandleScope scope(isolate); |
| 2413 switch (binary_type) { | 2442 Handle<Object> left = args.at<Object>(0); |
| 2414 case UNINITIALIZED: | 2443 Handle<Object> right = args.at<Object>(1); |
| 2415 return handle(Type::None(), isolate); | 2444 BinaryOpIC ic(isolate); |
| 2416 case SMI: | 2445 return ic.Transition(left, right); |
| 2417 return handle(Type::Smi(), isolate); | |
| 2418 case INT32: | |
| 2419 return handle(Type::Signed32(), isolate); | |
| 2420 case NUMBER: | |
| 2421 return handle(Type::Number(), isolate); | |
| 2422 case ODDBALL: | |
| 2423 return handle(Type::Optional( | |
| 2424 handle(Type::Union( | |
| 2425 handle(Type::Number(), isolate), | |
| 2426 handle(Type::String(), isolate)), isolate)), isolate); | |
| 2427 case STRING: | |
| 2428 return handle(Type::String(), isolate); | |
| 2429 case GENERIC: | |
| 2430 return handle(Type::Any(), isolate); | |
| 2431 } | |
| 2432 UNREACHABLE(); | |
| 2433 return handle(Type::Any(), isolate); | |
| 2434 } | 2446 } |
| 2435 | 2447 |
| 2436 | 2448 |
| 2437 void BinaryOpIC::StubInfoToType(int minor_key, | |
| 2438 Handle<Type>* left, | |
| 2439 Handle<Type>* right, | |
| 2440 Handle<Type>* result, | |
| 2441 Isolate* isolate) { | |
| 2442 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
| 2443 BinaryOpStub::decode_types_from_minor_key( | |
| 2444 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
| 2445 *left = TypeInfoToType(left_typeinfo, isolate); | |
| 2446 *right = TypeInfoToType(right_typeinfo, isolate); | |
| 2447 *result = TypeInfoToType(result_typeinfo, isolate); | |
| 2448 } | |
| 2449 | |
| 2450 | |
| 2451 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
| 2452 Token::Value op) { | |
| 2453 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
| 2454 if (type.IsSmi()) return BinaryOpIC::SMI; | |
| 2455 if (type.IsInteger32()) { | |
| 2456 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2457 return BinaryOpIC::INT32; | |
| 2458 } | |
| 2459 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
| 2460 if (type.IsString()) return BinaryOpIC::STRING; | |
| 2461 if (value->IsUndefined()) { | |
| 2462 if (op == Token::BIT_AND || | |
| 2463 op == Token::BIT_OR || | |
| 2464 op == Token::BIT_XOR || | |
| 2465 op == Token::SAR || | |
| 2466 op == Token::SHL || | |
| 2467 op == Token::SHR) { | |
| 2468 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2469 return BinaryOpIC::INT32; | |
| 2470 } | |
| 2471 return BinaryOpIC::ODDBALL; | |
| 2472 } | |
| 2473 return BinaryOpIC::GENERIC; | |
| 2474 } | |
| 2475 | |
| 2476 | |
| 2477 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
| 2478 Handle<Object> value, | |
| 2479 Token::Value op) { | |
| 2480 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
| 2481 if (old_type == BinaryOpIC::STRING) { | |
| 2482 if (new_type == BinaryOpIC::STRING) return new_type; | |
| 2483 return BinaryOpIC::GENERIC; | |
| 2484 } | |
| 2485 return Max(old_type, new_type); | |
| 2486 } | |
| 2487 | |
| 2488 | |
| 2489 #ifdef DEBUG | |
| 2490 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
| 2491 BinaryOpIC::TypeInfo right, | |
| 2492 Maybe<int32_t> fixed_right_arg, | |
| 2493 BinaryOpIC::TypeInfo result) { | |
| 2494 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
| 2495 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
| 2496 PrintF("->%s", BinaryOpIC::GetName(result)); | |
| 2497 } | |
| 2498 #endif | |
| 2499 | |
| 2500 | |
| 2501 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
| 2502 ASSERT(args.length() == 3); | |
| 2503 | |
| 2504 HandleScope scope(isolate); | |
| 2505 Handle<Object> left = args.at<Object>(0); | |
| 2506 Handle<Object> right = args.at<Object>(1); | |
| 2507 int key = args.smi_at(2); | |
| 2508 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
| 2509 | |
| 2510 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
| 2511 BinaryOpStub::decode_types_from_minor_key( | |
| 2512 key, &previous_left, &previous_right, &previous_result); | |
| 2513 | |
| 2514 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
| 2515 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
| 2516 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
| 2517 | |
| 2518 // STRING is only used for ADD operations. | |
| 2519 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
| 2520 op != Token::ADD) { | |
| 2521 new_left = new_right = BinaryOpIC::GENERIC; | |
| 2522 } | |
| 2523 | |
| 2524 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
| 2525 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
| 2526 | |
| 2527 Maybe<int> previous_fixed_right_arg = | |
| 2528 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
| 2529 | |
| 2530 int32_t value; | |
| 2531 bool new_has_fixed_right_arg = | |
| 2532 op == Token::MOD && | |
| 2533 right->ToInt32(&value) && | |
| 2534 BinaryOpStub::can_encode_arg_value(value) && | |
| 2535 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
| 2536 (previous_fixed_right_arg.has_value && | |
| 2537 previous_fixed_right_arg.value == value)); | |
| 2538 Maybe<int32_t> new_fixed_right_arg( | |
| 2539 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
| 2540 | |
| 2541 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
| 2542 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
| 2543 if (op == Token::DIV || | |
| 2544 op == Token::MUL || | |
| 2545 op == Token::SHR || | |
| 2546 SmiValuesAre32Bits()) { | |
| 2547 // Arithmetic on two Smi inputs has yielded a heap number. | |
| 2548 // That is the only way to get here from the Smi stub. | |
| 2549 // With 32-bit Smis, all overflows give heap numbers, but with | |
| 2550 // 31-bit Smis, most operations overflow to int32 results. | |
| 2551 result_type = BinaryOpIC::NUMBER; | |
| 2552 } else { | |
| 2553 // Other operations on SMIs that overflow yield int32s. | |
| 2554 result_type = BinaryOpIC::INT32; | |
| 2555 } | |
| 2556 } | |
| 2557 if (new_overall == BinaryOpIC::INT32 && | |
| 2558 previous_overall == BinaryOpIC::INT32) { | |
| 2559 if (new_left == previous_left && new_right == previous_right) { | |
| 2560 result_type = BinaryOpIC::NUMBER; | |
| 2561 } | |
| 2562 } | |
| 2563 } | |
| 2564 | |
| 2565 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
| 2566 Handle<Code> code = stub.GetCode(isolate); | |
| 2567 if (!code.is_null()) { | |
| 2568 #ifdef DEBUG | |
| 2569 if (FLAG_trace_ic) { | |
| 2570 PrintF("[BinaryOpIC in "); | |
| 2571 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
| 2572 PrintF(" "); | |
| 2573 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
| 2574 previous_result); | |
| 2575 PrintF(" => "); | |
| 2576 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
| 2577 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
| 2578 } | |
| 2579 #endif | |
| 2580 BinaryOpIC ic(isolate); | |
| 2581 ic.patch(*code); | |
| 2582 | |
| 2583 // Activate inlined smi code. | |
| 2584 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
| 2585 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
| 2586 } | |
| 2587 } | |
| 2588 | |
| 2589 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
| 2590 Object* builtin = NULL; // Initialization calms down the compiler. | |
| 2591 switch (op) { | |
| 2592 case Token::ADD: | |
| 2593 builtin = builtins->javascript_builtin(Builtins::ADD); | |
| 2594 break; | |
| 2595 case Token::SUB: | |
| 2596 builtin = builtins->javascript_builtin(Builtins::SUB); | |
| 2597 break; | |
| 2598 case Token::MUL: | |
| 2599 builtin = builtins->javascript_builtin(Builtins::MUL); | |
| 2600 break; | |
| 2601 case Token::DIV: | |
| 2602 builtin = builtins->javascript_builtin(Builtins::DIV); | |
| 2603 break; | |
| 2604 case Token::MOD: | |
| 2605 builtin = builtins->javascript_builtin(Builtins::MOD); | |
| 2606 break; | |
| 2607 case Token::BIT_AND: | |
| 2608 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
| 2609 break; | |
| 2610 case Token::BIT_OR: | |
| 2611 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
| 2612 break; | |
| 2613 case Token::BIT_XOR: | |
| 2614 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
| 2615 break; | |
| 2616 case Token::SHR: | |
| 2617 builtin = builtins->javascript_builtin(Builtins::SHR); | |
| 2618 break; | |
| 2619 case Token::SAR: | |
| 2620 builtin = builtins->javascript_builtin(Builtins::SAR); | |
| 2621 break; | |
| 2622 case Token::SHL: | |
| 2623 builtin = builtins->javascript_builtin(Builtins::SHL); | |
| 2624 break; | |
| 2625 default: | |
| 2626 UNREACHABLE(); | |
| 2627 } | |
| 2628 | |
| 2629 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
| 2630 | |
| 2631 bool caught_exception; | |
| 2632 Handle<Object> builtin_args[] = { right }; | |
| 2633 Handle<Object> result = Execution::Call(isolate, | |
| 2634 builtin_function, | |
| 2635 left, | |
| 2636 ARRAY_SIZE(builtin_args), | |
| 2637 builtin_args, | |
| 2638 &caught_exception); | |
| 2639 if (caught_exception) { | |
| 2640 return Failure::Exception(); | |
| 2641 } | |
| 2642 return *result; | |
| 2643 } | |
| 2644 | |
| 2645 | |
| 2646 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2449 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
| 2647 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2450 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| 2648 Code* code = NULL; | 2451 Code* code = NULL; |
| 2649 CHECK(stub.FindCodeInCache(&code, isolate)); | 2452 CHECK(stub.FindCodeInCache(&code, isolate)); |
| 2650 return code; | 2453 return code; |
| 2651 } | 2454 } |
| 2652 | 2455 |
| 2653 | 2456 |
| 2654 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2457 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
| 2655 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2458 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2933 } | 2736 } |
| 2934 | 2737 |
| 2935 | 2738 |
| 2936 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2739 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
| 2937 UNREACHABLE(); | 2740 UNREACHABLE(); |
| 2938 CHECK(false); | 2741 CHECK(false); |
| 2939 return isolate->heap()->undefined_value(); | 2742 return isolate->heap()->undefined_value(); |
| 2940 } | 2743 } |
| 2941 | 2744 |
| 2942 | 2745 |
| 2746 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2747 switch (op) { |
| 2748 default: |
| 2749 UNREACHABLE(); |
| 2750 case Token::ADD: |
| 2751 return Builtins::ADD; |
| 2752 break; |
| 2753 case Token::SUB: |
| 2754 return Builtins::SUB; |
| 2755 break; |
| 2756 case Token::MUL: |
| 2757 return Builtins::MUL; |
| 2758 break; |
| 2759 case Token::DIV: |
| 2760 return Builtins::DIV; |
| 2761 break; |
| 2762 case Token::MOD: |
| 2763 return Builtins::MOD; |
| 2764 break; |
| 2765 case Token::BIT_OR: |
| 2766 return Builtins::BIT_OR; |
| 2767 break; |
| 2768 case Token::BIT_AND: |
| 2769 return Builtins::BIT_AND; |
| 2770 break; |
| 2771 case Token::BIT_XOR: |
| 2772 return Builtins::BIT_XOR; |
| 2773 break; |
| 2774 case Token::SAR: |
| 2775 return Builtins::SAR; |
| 2776 break; |
| 2777 case Token::SHR: |
| 2778 return Builtins::SHR; |
| 2779 break; |
| 2780 case Token::SHL: |
| 2781 return Builtins::SHL; |
| 2782 break; |
| 2783 } |
| 2784 } |
| 2785 |
| 2786 |
| 2943 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2787 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
| 2944 Code::ExtraICState extra_ic_state) { | 2788 Code::ExtraICState extra_ic_state) { |
| 2945 ToBooleanStub stub(extra_ic_state); | 2789 ToBooleanStub stub(extra_ic_state); |
| 2946 bool to_boolean_value = stub.UpdateStatus(object); | 2790 bool to_boolean_value = stub.UpdateStatus(object); |
| 2947 Handle<Code> code = stub.GetCode(isolate()); | 2791 Handle<Code> code = stub.GetCode(isolate()); |
| 2948 set_target(*code); | 2792 set_target(*code); |
| 2949 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2793 return Smi::FromInt(to_boolean_value ? 1 : 0); |
| 2950 } | 2794 } |
| 2951 | 2795 |
| 2952 | 2796 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2967 #undef ADDR | 2811 #undef ADDR |
| 2968 }; | 2812 }; |
| 2969 | 2813 |
| 2970 | 2814 |
| 2971 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2815 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2972 return IC_utilities[id]; | 2816 return IC_utilities[id]; |
| 2973 } | 2817 } |
| 2974 | 2818 |
| 2975 | 2819 |
| 2976 } } // namespace v8::internal | 2820 } } // namespace v8::internal |
| OLD | NEW |