| 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 2311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2322 StrictModeFlag strict_mode = ic.strict_mode(); | 2322 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2323 return Runtime::SetObjectProperty(isolate, | 2323 return Runtime::SetObjectProperty(isolate, |
| 2324 object, | 2324 object, |
| 2325 key, | 2325 key, |
| 2326 value, | 2326 value, |
| 2327 NONE, | 2327 NONE, |
| 2328 strict_mode); | 2328 strict_mode); |
| 2329 } | 2329 } |
| 2330 | 2330 |
| 2331 | 2331 |
| 2332 void BinaryOpIC::patch(Code* code) { | |
| 2333 set_target(code); | |
| 2334 } | |
| 2335 | |
| 2336 | |
| 2337 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2332 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 2338 switch (type_info) { | 2333 switch (type_info) { |
| 2339 case UNINITIALIZED: return "Uninitialized"; | 2334 case UNINITIALIZED: return "Uninitialized"; |
| 2340 case SMI: return "Smi"; | 2335 case SMI: return "Smi"; |
| 2341 case INT32: return "Int32"; | 2336 case INT32: return "Int32"; |
| 2342 case NUMBER: return "Number"; | 2337 case NUMBER: return "Number"; |
| 2343 case ODDBALL: return "Oddball"; | 2338 case ODDBALL: return "Oddball"; |
| 2344 case STRING: return "String"; | 2339 case STRING: return "String"; |
| 2345 case GENERIC: return "Generic"; | 2340 case GENERIC: return "Generic"; |
| 2346 default: return "Invalid"; | 2341 default: return "Invalid"; |
| 2347 } | 2342 } |
| 2348 } | 2343 } |
| 2349 | 2344 |
| 2350 | 2345 |
| 2351 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2346 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2352 switch (type_info) { | 2347 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2353 case UNINITIALIZED: | 2348 BinaryOpStub stub(extra_ic_state); |
| 2354 return ::v8::internal::UNINITIALIZED; | 2349 |
| 2355 case SMI: | 2350 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2356 case INT32: | 2351 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2357 case NUMBER: | 2352 |
| 2358 case ODDBALL: | 2353 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
| 2359 case STRING: | 2354 |
| 2360 return MONOMORPHIC; | 2355 #ifdef DEBUG |
| 2361 case GENERIC: | 2356 if (FLAG_trace_ic) { |
| 2362 return ::v8::internal::GENERIC; | 2357 char buffer[100]; |
| 2358 NoAllocationStringAllocator allocator(buffer, |
| 2359 static_cast<unsigned>(sizeof(buffer))); |
| 2360 StringStream stream(&allocator); |
| 2361 stream.Add("["); |
| 2362 stub.PrintName(&stream); |
| 2363 |
| 2364 stub.UpdateStatus(left, right, result); |
| 2365 |
| 2366 stream.Add(" => "); |
| 2367 stub.PrintState(&stream); |
| 2368 stream.Add(" "); |
| 2369 stream.OutputToStdOut(); |
| 2370 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2371 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2372 PrintF("]\n"); |
| 2373 } else { |
| 2374 stub.UpdateStatus(left, right, result); |
| 2363 } | 2375 } |
| 2364 UNREACHABLE(); | 2376 #else |
| 2365 return ::v8::internal::UNINITIALIZED; | 2377 stub.UpdateStatus(left, right, result); |
| 2378 #endif |
| 2379 |
| 2380 Handle<Code> code = stub.GetCode(isolate()); |
| 2381 set_target(*code); |
| 2382 |
| 2383 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2384 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2385 |
| 2386 if (!smi_was_enabled && enable_smi) { |
| 2387 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2388 } else if (smi_was_enabled && !enable_smi) { |
| 2389 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2390 } |
| 2391 |
| 2392 return result.has_value |
| 2393 ? static_cast<MaybeObject*>(*result.value) |
| 2394 : Failure::Exception(); |
| 2366 } | 2395 } |
| 2367 | 2396 |
| 2368 | 2397 |
| 2369 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2398 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2370 Isolate* isolate) { | 2399 HandleScope scope(isolate); |
| 2371 switch (binary_type) { | 2400 Handle<Object> left = args.at<Object>(0); |
| 2372 case UNINITIALIZED: | 2401 Handle<Object> right = args.at<Object>(1); |
| 2373 return handle(Type::None(), isolate); | 2402 BinaryOpIC ic(isolate); |
| 2374 case SMI: | 2403 return ic.Transition(left, right); |
| 2375 return handle(Type::Smi(), isolate); | |
| 2376 case INT32: | |
| 2377 return handle(Type::Signed32(), isolate); | |
| 2378 case NUMBER: | |
| 2379 return handle(Type::Number(), isolate); | |
| 2380 case ODDBALL: | |
| 2381 return handle(Type::Optional( | |
| 2382 handle(Type::Union( | |
| 2383 handle(Type::Number(), isolate), | |
| 2384 handle(Type::String(), isolate)), isolate)), isolate); | |
| 2385 case STRING: | |
| 2386 return handle(Type::String(), isolate); | |
| 2387 case GENERIC: | |
| 2388 return handle(Type::Any(), isolate); | |
| 2389 } | |
| 2390 UNREACHABLE(); | |
| 2391 return handle(Type::Any(), isolate); | |
| 2392 } | 2404 } |
| 2393 | 2405 |
| 2394 | 2406 |
| 2395 void BinaryOpIC::StubInfoToType(int minor_key, | |
| 2396 Handle<Type>* left, | |
| 2397 Handle<Type>* right, | |
| 2398 Handle<Type>* result, | |
| 2399 Isolate* isolate) { | |
| 2400 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
| 2401 BinaryOpStub::decode_types_from_minor_key( | |
| 2402 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
| 2403 *left = TypeInfoToType(left_typeinfo, isolate); | |
| 2404 *right = TypeInfoToType(right_typeinfo, isolate); | |
| 2405 *result = TypeInfoToType(result_typeinfo, isolate); | |
| 2406 } | |
| 2407 | |
| 2408 | |
| 2409 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
| 2410 Token::Value op) { | |
| 2411 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
| 2412 if (type.IsSmi()) return BinaryOpIC::SMI; | |
| 2413 if (type.IsInteger32()) { | |
| 2414 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2415 return BinaryOpIC::INT32; | |
| 2416 } | |
| 2417 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
| 2418 if (type.IsString()) return BinaryOpIC::STRING; | |
| 2419 if (value->IsUndefined()) { | |
| 2420 if (op == Token::BIT_AND || | |
| 2421 op == Token::BIT_OR || | |
| 2422 op == Token::BIT_XOR || | |
| 2423 op == Token::SAR || | |
| 2424 op == Token::SHL || | |
| 2425 op == Token::SHR) { | |
| 2426 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2427 return BinaryOpIC::INT32; | |
| 2428 } | |
| 2429 return BinaryOpIC::ODDBALL; | |
| 2430 } | |
| 2431 return BinaryOpIC::GENERIC; | |
| 2432 } | |
| 2433 | |
| 2434 | |
| 2435 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
| 2436 Handle<Object> value, | |
| 2437 Token::Value op) { | |
| 2438 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
| 2439 if (old_type == BinaryOpIC::STRING) { | |
| 2440 if (new_type == BinaryOpIC::STRING) return new_type; | |
| 2441 return BinaryOpIC::GENERIC; | |
| 2442 } | |
| 2443 return Max(old_type, new_type); | |
| 2444 } | |
| 2445 | |
| 2446 | |
| 2447 #ifdef DEBUG | |
| 2448 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
| 2449 BinaryOpIC::TypeInfo right, | |
| 2450 Maybe<int32_t> fixed_right_arg, | |
| 2451 BinaryOpIC::TypeInfo result) { | |
| 2452 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
| 2453 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
| 2454 PrintF("->%s", BinaryOpIC::GetName(result)); | |
| 2455 } | |
| 2456 #endif | |
| 2457 | |
| 2458 | |
| 2459 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
| 2460 ASSERT(args.length() == 3); | |
| 2461 | |
| 2462 HandleScope scope(isolate); | |
| 2463 Handle<Object> left = args.at<Object>(0); | |
| 2464 Handle<Object> right = args.at<Object>(1); | |
| 2465 int key = args.smi_at(2); | |
| 2466 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
| 2467 | |
| 2468 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
| 2469 BinaryOpStub::decode_types_from_minor_key( | |
| 2470 key, &previous_left, &previous_right, &previous_result); | |
| 2471 | |
| 2472 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
| 2473 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
| 2474 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
| 2475 | |
| 2476 // STRING is only used for ADD operations. | |
| 2477 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
| 2478 op != Token::ADD) { | |
| 2479 new_left = new_right = BinaryOpIC::GENERIC; | |
| 2480 } | |
| 2481 | |
| 2482 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
| 2483 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
| 2484 | |
| 2485 Maybe<int> previous_fixed_right_arg = | |
| 2486 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
| 2487 | |
| 2488 int32_t value; | |
| 2489 bool new_has_fixed_right_arg = | |
| 2490 op == Token::MOD && | |
| 2491 right->ToInt32(&value) && | |
| 2492 BinaryOpStub::can_encode_arg_value(value) && | |
| 2493 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
| 2494 (previous_fixed_right_arg.has_value && | |
| 2495 previous_fixed_right_arg.value == value)); | |
| 2496 Maybe<int32_t> new_fixed_right_arg( | |
| 2497 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
| 2498 | |
| 2499 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
| 2500 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
| 2501 if (op == Token::DIV || | |
| 2502 op == Token::MUL || | |
| 2503 op == Token::SHR || | |
| 2504 SmiValuesAre32Bits()) { | |
| 2505 // Arithmetic on two Smi inputs has yielded a heap number. | |
| 2506 // That is the only way to get here from the Smi stub. | |
| 2507 // With 32-bit Smis, all overflows give heap numbers, but with | |
| 2508 // 31-bit Smis, most operations overflow to int32 results. | |
| 2509 result_type = BinaryOpIC::NUMBER; | |
| 2510 } else { | |
| 2511 // Other operations on SMIs that overflow yield int32s. | |
| 2512 result_type = BinaryOpIC::INT32; | |
| 2513 } | |
| 2514 } | |
| 2515 if (new_overall == BinaryOpIC::INT32 && | |
| 2516 previous_overall == BinaryOpIC::INT32) { | |
| 2517 if (new_left == previous_left && new_right == previous_right) { | |
| 2518 result_type = BinaryOpIC::NUMBER; | |
| 2519 } | |
| 2520 } | |
| 2521 } | |
| 2522 | |
| 2523 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
| 2524 Handle<Code> code = stub.GetCode(isolate); | |
| 2525 if (!code.is_null()) { | |
| 2526 #ifdef DEBUG | |
| 2527 if (FLAG_trace_ic) { | |
| 2528 PrintF("[BinaryOpIC in "); | |
| 2529 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
| 2530 PrintF(" "); | |
| 2531 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
| 2532 previous_result); | |
| 2533 PrintF(" => "); | |
| 2534 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
| 2535 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
| 2536 } | |
| 2537 #endif | |
| 2538 BinaryOpIC ic(isolate); | |
| 2539 ic.patch(*code); | |
| 2540 | |
| 2541 // Activate inlined smi code. | |
| 2542 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
| 2543 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
| 2544 } | |
| 2545 } | |
| 2546 | |
| 2547 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
| 2548 Object* builtin = NULL; // Initialization calms down the compiler. | |
| 2549 switch (op) { | |
| 2550 case Token::ADD: | |
| 2551 builtin = builtins->javascript_builtin(Builtins::ADD); | |
| 2552 break; | |
| 2553 case Token::SUB: | |
| 2554 builtin = builtins->javascript_builtin(Builtins::SUB); | |
| 2555 break; | |
| 2556 case Token::MUL: | |
| 2557 builtin = builtins->javascript_builtin(Builtins::MUL); | |
| 2558 break; | |
| 2559 case Token::DIV: | |
| 2560 builtin = builtins->javascript_builtin(Builtins::DIV); | |
| 2561 break; | |
| 2562 case Token::MOD: | |
| 2563 builtin = builtins->javascript_builtin(Builtins::MOD); | |
| 2564 break; | |
| 2565 case Token::BIT_AND: | |
| 2566 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
| 2567 break; | |
| 2568 case Token::BIT_OR: | |
| 2569 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
| 2570 break; | |
| 2571 case Token::BIT_XOR: | |
| 2572 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
| 2573 break; | |
| 2574 case Token::SHR: | |
| 2575 builtin = builtins->javascript_builtin(Builtins::SHR); | |
| 2576 break; | |
| 2577 case Token::SAR: | |
| 2578 builtin = builtins->javascript_builtin(Builtins::SAR); | |
| 2579 break; | |
| 2580 case Token::SHL: | |
| 2581 builtin = builtins->javascript_builtin(Builtins::SHL); | |
| 2582 break; | |
| 2583 default: | |
| 2584 UNREACHABLE(); | |
| 2585 } | |
| 2586 | |
| 2587 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
| 2588 | |
| 2589 bool caught_exception; | |
| 2590 Handle<Object> builtin_args[] = { right }; | |
| 2591 Handle<Object> result = Execution::Call(isolate, | |
| 2592 builtin_function, | |
| 2593 left, | |
| 2594 ARRAY_SIZE(builtin_args), | |
| 2595 builtin_args, | |
| 2596 &caught_exception); | |
| 2597 if (caught_exception) { | |
| 2598 return Failure::Exception(); | |
| 2599 } | |
| 2600 return *result; | |
| 2601 } | |
| 2602 | |
| 2603 | |
| 2604 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2407 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
| 2605 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2408 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| 2606 Code* code = NULL; | 2409 Code* code = NULL; |
| 2607 CHECK(stub.FindCodeInCache(&code, isolate)); | 2410 CHECK(stub.FindCodeInCache(&code, isolate)); |
| 2608 return code; | 2411 return code; |
| 2609 } | 2412 } |
| 2610 | 2413 |
| 2611 | 2414 |
| 2612 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2415 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
| 2613 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2416 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2891 } | 2694 } |
| 2892 | 2695 |
| 2893 | 2696 |
| 2894 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2697 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
| 2895 UNREACHABLE(); | 2698 UNREACHABLE(); |
| 2896 CHECK(false); | 2699 CHECK(false); |
| 2897 return isolate->heap()->undefined_value(); | 2700 return isolate->heap()->undefined_value(); |
| 2898 } | 2701 } |
| 2899 | 2702 |
| 2900 | 2703 |
| 2704 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2705 switch (op) { |
| 2706 default: |
| 2707 UNREACHABLE(); |
| 2708 case Token::ADD: |
| 2709 return Builtins::ADD; |
| 2710 break; |
| 2711 case Token::SUB: |
| 2712 return Builtins::SUB; |
| 2713 break; |
| 2714 case Token::MUL: |
| 2715 return Builtins::MUL; |
| 2716 break; |
| 2717 case Token::DIV: |
| 2718 return Builtins::DIV; |
| 2719 break; |
| 2720 case Token::MOD: |
| 2721 return Builtins::MOD; |
| 2722 break; |
| 2723 case Token::BIT_OR: |
| 2724 return Builtins::BIT_OR; |
| 2725 break; |
| 2726 case Token::BIT_AND: |
| 2727 return Builtins::BIT_AND; |
| 2728 break; |
| 2729 case Token::BIT_XOR: |
| 2730 return Builtins::BIT_XOR; |
| 2731 break; |
| 2732 case Token::SAR: |
| 2733 return Builtins::SAR; |
| 2734 break; |
| 2735 case Token::SHR: |
| 2736 return Builtins::SHR; |
| 2737 break; |
| 2738 case Token::SHL: |
| 2739 return Builtins::SHL; |
| 2740 break; |
| 2741 } |
| 2742 } |
| 2743 |
| 2744 |
| 2901 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2745 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
| 2902 Code::ExtraICState extra_ic_state) { | 2746 Code::ExtraICState extra_ic_state) { |
| 2903 ToBooleanStub stub(extra_ic_state); | 2747 ToBooleanStub stub(extra_ic_state); |
| 2904 bool to_boolean_value = stub.UpdateStatus(object); | 2748 bool to_boolean_value = stub.UpdateStatus(object); |
| 2905 Handle<Code> code = stub.GetCode(isolate()); | 2749 Handle<Code> code = stub.GetCode(isolate()); |
| 2906 set_target(*code); | 2750 set_target(*code); |
| 2907 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2751 return Smi::FromInt(to_boolean_value ? 1 : 0); |
| 2908 } | 2752 } |
| 2909 | 2753 |
| 2910 | 2754 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2925 #undef ADDR | 2769 #undef ADDR |
| 2926 }; | 2770 }; |
| 2927 | 2771 |
| 2928 | 2772 |
| 2929 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2773 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2930 return IC_utilities[id]; | 2774 return IC_utilities[id]; |
| 2931 } | 2775 } |
| 2932 | 2776 |
| 2933 | 2777 |
| 2934 } } // namespace v8::internal | 2778 } } // namespace v8::internal |
| OLD | NEW |