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 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 void KeyedStoreIC::Clear(Address address, Code* target) { | 407 void KeyedStoreIC::Clear(Address address, Code* target) { |
408 if (target->ic_state() == UNINITIALIZED) return; | 408 if (target->ic_state() == UNINITIALIZED) return; |
409 SetTargetAtAddress(address, | 409 SetTargetAtAddress(address, |
410 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) | 410 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) |
411 ? initialize_stub_strict() | 411 ? initialize_stub_strict() |
412 : initialize_stub()); | 412 : initialize_stub()); |
413 } | 413 } |
414 | 414 |
415 | 415 |
416 void CompareIC::Clear(Address address, Code* target) { | 416 void CompareIC::Clear(Address address, Code* target) { |
417 // Only clear ICCompareStubs, we currently cannot clear generic CompareStubs. | 417 ASSERT(target->major_key() == CodeStub::CompareIC); |
418 if (target->major_key() != CodeStub::CompareIC) return; | 418 CompareIC::State handler_state; |
| 419 Token::Value op; |
| 420 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, |
| 421 &handler_state, &op); |
419 // Only clear CompareICs that can retain objects. | 422 // Only clear CompareICs that can retain objects. |
420 if (target->compare_state() != KNOWN_OBJECTS) return; | 423 if (handler_state != KNOWN_OBJECTS) return; |
421 Token::Value op = CompareIC::ComputeOperation(target); | |
422 SetTargetAtAddress(address, GetRawUninitialized(op)); | 424 SetTargetAtAddress(address, GetRawUninitialized(op)); |
423 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); | 425 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); |
424 } | 426 } |
425 | 427 |
426 | 428 |
427 static bool HasInterceptorGetter(JSObject* object) { | 429 static bool HasInterceptorGetter(JSObject* object) { |
428 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 430 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
429 } | 431 } |
430 | 432 |
431 | 433 |
(...skipping 1868 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2300 | 2302 |
2301 void BinaryOpIC::patch(Code* code) { | 2303 void BinaryOpIC::patch(Code* code) { |
2302 set_target(code); | 2304 set_target(code); |
2303 } | 2305 } |
2304 | 2306 |
2305 | 2307 |
2306 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2308 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
2307 switch (type_info) { | 2309 switch (type_info) { |
2308 case UNINITIALIZED: return "Uninitialized"; | 2310 case UNINITIALIZED: return "Uninitialized"; |
2309 case SMI: return "SMI"; | 2311 case SMI: return "SMI"; |
2310 case INT32: return "Int32s"; | 2312 case INT32: return "Int32"; |
2311 case HEAP_NUMBER: return "HeapNumbers"; | 2313 case HEAP_NUMBER: return "HeapNumber"; |
2312 case ODDBALL: return "Oddball"; | 2314 case ODDBALL: return "Oddball"; |
2313 case BOTH_STRING: return "BothStrings"; | 2315 case STRING: return "String"; |
2314 case STRING: return "Strings"; | |
2315 case GENERIC: return "Generic"; | 2316 case GENERIC: return "Generic"; |
2316 default: return "Invalid"; | 2317 default: return "Invalid"; |
2317 } | 2318 } |
2318 } | 2319 } |
2319 | 2320 |
2320 | 2321 |
2321 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2322 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { |
2322 switch (type_info) { | 2323 switch (type_info) { |
2323 case UNINITIALIZED: | 2324 case UNINITIALIZED: |
2324 return ::v8::internal::UNINITIALIZED; | 2325 return ::v8::internal::UNINITIALIZED; |
2325 case SMI: | 2326 case SMI: |
2326 case INT32: | 2327 case INT32: |
2327 case HEAP_NUMBER: | 2328 case HEAP_NUMBER: |
2328 case ODDBALL: | 2329 case ODDBALL: |
2329 case BOTH_STRING: | |
2330 case STRING: | 2330 case STRING: |
2331 return MONOMORPHIC; | 2331 return MONOMORPHIC; |
2332 case GENERIC: | 2332 case GENERIC: |
2333 return MEGAMORPHIC; | 2333 return MEGAMORPHIC; |
2334 } | 2334 } |
2335 UNREACHABLE(); | 2335 UNREACHABLE(); |
2336 return ::v8::internal::UNINITIALIZED; | 2336 return ::v8::internal::UNINITIALIZED; |
2337 } | 2337 } |
2338 | 2338 |
2339 | 2339 |
2340 BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x, | |
2341 BinaryOpIC::TypeInfo y) { | |
2342 if (x == UNINITIALIZED) return y; | |
2343 if (y == UNINITIALIZED) return x; | |
2344 if (x == y) return x; | |
2345 if (x == BOTH_STRING && y == STRING) return STRING; | |
2346 if (x == STRING && y == BOTH_STRING) return STRING; | |
2347 if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) { | |
2348 return GENERIC; | |
2349 } | |
2350 if (x > y) return x; | |
2351 return y; | |
2352 } | |
2353 | |
2354 | |
2355 BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left, | |
2356 Handle<Object> right) { | |
2357 ::v8::internal::TypeInfo left_type = | |
2358 ::v8::internal::TypeInfo::TypeFromValue(left); | |
2359 ::v8::internal::TypeInfo right_type = | |
2360 ::v8::internal::TypeInfo::TypeFromValue(right); | |
2361 | |
2362 if (left_type.IsSmi() && right_type.IsSmi()) { | |
2363 return SMI; | |
2364 } | |
2365 | |
2366 if (left_type.IsInteger32() && right_type.IsInteger32()) { | |
2367 // Platforms with 32-bit Smis have no distinct INT32 type. | |
2368 if (kSmiValueSize == 32) return SMI; | |
2369 return INT32; | |
2370 } | |
2371 | |
2372 if (left_type.IsNumber() && right_type.IsNumber()) { | |
2373 return HEAP_NUMBER; | |
2374 } | |
2375 | |
2376 // Patching for fast string ADD makes sense even if only one of the | |
2377 // arguments is a string. | |
2378 if (left_type.IsString()) { | |
2379 return right_type.IsString() ? BOTH_STRING : STRING; | |
2380 } else if (right_type.IsString()) { | |
2381 return STRING; | |
2382 } | |
2383 | |
2384 // Check for oddball objects. | |
2385 if (left->IsUndefined() && right->IsNumber()) return ODDBALL; | |
2386 if (left->IsNumber() && right->IsUndefined()) return ODDBALL; | |
2387 | |
2388 return GENERIC; | |
2389 } | |
2390 | |
2391 | |
2392 RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { | 2340 RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { |
2393 ASSERT(args.length() == 4); | 2341 ASSERT(args.length() == 4); |
2394 | 2342 |
2395 HandleScope scope(isolate); | 2343 HandleScope scope(isolate); |
2396 Handle<Object> operand = args.at<Object>(0); | 2344 Handle<Object> operand = args.at<Object>(0); |
2397 Token::Value op = static_cast<Token::Value>(args.smi_at(1)); | 2345 Token::Value op = static_cast<Token::Value>(args.smi_at(1)); |
2398 UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2)); | 2346 UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2)); |
2399 UnaryOpIC::TypeInfo previous_type = | 2347 UnaryOpIC::TypeInfo previous_type = |
2400 static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3)); | 2348 static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3)); |
2401 | 2349 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2433 | 2381 |
2434 bool caught_exception; | 2382 bool caught_exception; |
2435 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL, | 2383 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL, |
2436 &caught_exception); | 2384 &caught_exception); |
2437 if (caught_exception) { | 2385 if (caught_exception) { |
2438 return Failure::Exception(); | 2386 return Failure::Exception(); |
2439 } | 2387 } |
2440 return *result; | 2388 return *result; |
2441 } | 2389 } |
2442 | 2390 |
| 2391 |
| 2392 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, |
| 2393 Token::Value op) { |
| 2394 ::v8::internal::TypeInfo type = |
| 2395 ::v8::internal::TypeInfo::TypeFromValue(value); |
| 2396 if (type.IsSmi()) return BinaryOpIC::SMI; |
| 2397 if (type.IsInteger32()) { |
| 2398 if (kSmiValueSize == 32) return BinaryOpIC::SMI; |
| 2399 return BinaryOpIC::INT32; |
| 2400 } |
| 2401 if (type.IsNumber()) return BinaryOpIC::HEAP_NUMBER; |
| 2402 if (type.IsString()) return BinaryOpIC::STRING; |
| 2403 if (value->IsUndefined()) { |
| 2404 if (op == Token::BIT_AND || |
| 2405 op == Token::BIT_OR || |
| 2406 op == Token::BIT_XOR || |
| 2407 op == Token::SAR || |
| 2408 op == Token::SHL || |
| 2409 op == Token::SHR) { |
| 2410 if (kSmiValueSize == 32) return BinaryOpIC::SMI; |
| 2411 return BinaryOpIC::INT32; |
| 2412 } |
| 2413 return BinaryOpIC::ODDBALL; |
| 2414 } |
| 2415 return BinaryOpIC::GENERIC; |
| 2416 } |
| 2417 |
| 2418 |
2443 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | 2419 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { |
2444 ASSERT(args.length() == 5); | 2420 ASSERT(args.length() == 3); |
2445 | 2421 |
2446 HandleScope scope(isolate); | 2422 HandleScope scope(isolate); |
2447 Handle<Object> left = args.at<Object>(0); | 2423 Handle<Object> left = args.at<Object>(0); |
2448 Handle<Object> right = args.at<Object>(1); | 2424 Handle<Object> right = args.at<Object>(1); |
2449 int key = args.smi_at(2); | 2425 int key = args.smi_at(2); |
2450 Token::Value op = static_cast<Token::Value>(args.smi_at(3)); | 2426 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); |
2451 BinaryOpIC::TypeInfo previous_type = | 2427 BinaryOpIC::TypeInfo previous_left, previous_right, unused_previous_result; |
2452 static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4)); | 2428 BinaryOpStub::decode_types_from_minor_key( |
| 2429 key, &previous_left, &previous_right, &unused_previous_result); |
2453 | 2430 |
2454 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right); | 2431 BinaryOpIC::TypeInfo new_left = TypeInfoFromValue(left, op); |
2455 type = BinaryOpIC::JoinTypes(type, previous_type); | 2432 BinaryOpIC::TypeInfo new_right = TypeInfoFromValue(right, op); |
| 2433 // Transition to more general type of {new, previous}. |
| 2434 new_left = Max(new_left, previous_left); |
| 2435 new_right = Max(new_right, previous_right); |
2456 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | 2436 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; |
2457 if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) && | 2437 |
| 2438 // STRING is only used for ADD operations. |
| 2439 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && |
2458 op != Token::ADD) { | 2440 op != Token::ADD) { |
2459 type = BinaryOpIC::GENERIC; | 2441 new_left = new_right = BinaryOpIC::GENERIC; |
2460 } | 2442 } |
2461 if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) { | 2443 |
| 2444 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); |
| 2445 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); |
| 2446 |
| 2447 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { |
2462 if (op == Token::DIV || | 2448 if (op == Token::DIV || |
2463 op == Token::MUL || | 2449 op == Token::MUL || |
2464 op == Token::SHR || | 2450 op == Token::SHR || |
2465 kSmiValueSize == 32) { | 2451 kSmiValueSize == 32) { |
2466 // Arithmetic on two Smi inputs has yielded a heap number. | 2452 // Arithmetic on two Smi inputs has yielded a heap number. |
2467 // That is the only way to get here from the Smi stub. | 2453 // That is the only way to get here from the Smi stub. |
2468 // With 32-bit Smis, all overflows give heap numbers, but with | 2454 // With 32-bit Smis, all overflows give heap numbers, but with |
2469 // 31-bit Smis, most operations overflow to int32 results. | 2455 // 31-bit Smis, most operations overflow to int32 results. |
2470 result_type = BinaryOpIC::HEAP_NUMBER; | 2456 result_type = BinaryOpIC::HEAP_NUMBER; |
2471 } else { | 2457 } else { |
2472 // Other operations on SMIs that overflow yield int32s. | 2458 // Other operations on SMIs that overflow yield int32s. |
2473 result_type = BinaryOpIC::INT32; | 2459 result_type = BinaryOpIC::INT32; |
2474 } | 2460 } |
2475 } | 2461 } |
2476 if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) { | 2462 if (new_overall == BinaryOpIC::INT32 && |
2477 // We must be here because an operation on two INT32 types overflowed. | 2463 previous_overall == BinaryOpIC::INT32) { |
2478 result_type = BinaryOpIC::HEAP_NUMBER; | 2464 if (new_left == previous_left && |
| 2465 new_right == previous_right) { |
| 2466 result_type = BinaryOpIC::HEAP_NUMBER; |
| 2467 } else { |
| 2468 result_type = BinaryOpIC::INT32; |
| 2469 } |
2479 } | 2470 } |
2480 | 2471 |
2481 BinaryOpStub stub(key, type, result_type); | 2472 BinaryOpStub stub(key, new_left, new_right, result_type); |
2482 Handle<Code> code = stub.GetCode(); | 2473 Handle<Code> code = stub.GetCode(); |
2483 if (!code.is_null()) { | 2474 if (!code.is_null()) { |
| 2475 #ifdef DEBUG |
2484 if (FLAG_trace_ic) { | 2476 if (FLAG_trace_ic) { |
2485 PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n", | 2477 PrintF("[BinaryOpIC in "); |
2486 BinaryOpIC::GetName(previous_type), | 2478 JavaScriptFrame::PrintTop(stdout, false, true); |
2487 BinaryOpIC::GetName(type), | 2479 PrintF(" ((%s+%s)->((%s+%s)->%s))#%s @ %p]\n", |
| 2480 BinaryOpIC::GetName(previous_left), |
| 2481 BinaryOpIC::GetName(previous_right), |
| 2482 BinaryOpIC::GetName(new_left), |
| 2483 BinaryOpIC::GetName(new_right), |
2488 BinaryOpIC::GetName(result_type), | 2484 BinaryOpIC::GetName(result_type), |
2489 Token::Name(op)); | 2485 Token::Name(op), |
| 2486 static_cast<void*>(*code)); |
2490 } | 2487 } |
| 2488 #endif |
2491 BinaryOpIC ic(isolate); | 2489 BinaryOpIC ic(isolate); |
2492 ic.patch(*code); | 2490 ic.patch(*code); |
2493 | 2491 |
2494 // Activate inlined smi code. | 2492 // Activate inlined smi code. |
2495 if (previous_type == BinaryOpIC::UNINITIALIZED) { | 2493 if (previous_overall == BinaryOpIC::UNINITIALIZED) { |
2496 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | 2494 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); |
2497 } | 2495 } |
2498 } | 2496 } |
2499 | 2497 |
2500 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( | 2498 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( |
2501 isolate->thread_local_top()->context_->builtins(), isolate); | 2499 isolate->thread_local_top()->context_->builtins(), isolate); |
2502 Object* builtin = NULL; // Initialization calms down the compiler. | 2500 Object* builtin = NULL; // Initialization calms down the compiler. |
2503 switch (op) { | 2501 switch (op) { |
2504 case Token::ADD: | 2502 case Token::ADD: |
2505 builtin = builtins->javascript_builtin(Builtins::ADD); | 2503 builtin = builtins->javascript_builtin(Builtins::ADD); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2548 builtin_args, | 2546 builtin_args, |
2549 &caught_exception); | 2547 &caught_exception); |
2550 if (caught_exception) { | 2548 if (caught_exception) { |
2551 return Failure::Exception(); | 2549 return Failure::Exception(); |
2552 } | 2550 } |
2553 return *result; | 2551 return *result; |
2554 } | 2552 } |
2555 | 2553 |
2556 | 2554 |
2557 Code* CompareIC::GetRawUninitialized(Token::Value op) { | 2555 Code* CompareIC::GetRawUninitialized(Token::Value op) { |
2558 ICCompareStub stub(op, UNINITIALIZED); | 2556 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2559 Code* code = NULL; | 2557 Code* code = NULL; |
2560 CHECK(stub.FindCodeInCache(&code)); | 2558 CHECK(stub.FindCodeInCache(&code)); |
2561 return code; | 2559 return code; |
2562 } | 2560 } |
2563 | 2561 |
2564 | 2562 |
2565 Handle<Code> CompareIC::GetUninitialized(Token::Value op) { | 2563 Handle<Code> CompareIC::GetUninitialized(Token::Value op) { |
2566 ICCompareStub stub(op, UNINITIALIZED); | 2564 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2567 return stub.GetCode(); | 2565 return stub.GetCode(); |
2568 } | 2566 } |
2569 | 2567 |
2570 | 2568 |
2571 CompareIC::State CompareIC::ComputeState(Code* target) { | |
2572 int key = target->major_key(); | |
2573 if (key == CodeStub::Compare) return GENERIC; | |
2574 ASSERT(key == CodeStub::CompareIC); | |
2575 return static_cast<State>(target->compare_state()); | |
2576 } | |
2577 | |
2578 | |
2579 Token::Value CompareIC::ComputeOperation(Code* target) { | |
2580 ASSERT(target->major_key() == CodeStub::CompareIC); | |
2581 return static_cast<Token::Value>( | |
2582 target->compare_operation() + Token::EQ); | |
2583 } | |
2584 | |
2585 | |
2586 const char* CompareIC::GetStateName(State state) { | 2569 const char* CompareIC::GetStateName(State state) { |
2587 switch (state) { | 2570 switch (state) { |
2588 case UNINITIALIZED: return "UNINITIALIZED"; | 2571 case UNINITIALIZED: return "UNINITIALIZED"; |
2589 case SMIS: return "SMIS"; | 2572 case SMI: return "SMI"; |
2590 case HEAP_NUMBERS: return "HEAP_NUMBERS"; | 2573 case HEAP_NUMBER: return "HEAP_NUMBER"; |
2591 case OBJECTS: return "OBJECTS"; | 2574 case OBJECT: return "OBJECTS"; |
2592 case KNOWN_OBJECTS: return "KNOWN_OBJECTS"; | 2575 case KNOWN_OBJECTS: return "KNOWN_OBJECTS"; |
2593 case SYMBOLS: return "SYMBOLS"; | 2576 case SYMBOL: return "SYMBOL"; |
2594 case STRINGS: return "STRINGS"; | 2577 case STRING: return "STRING"; |
2595 case GENERIC: return "GENERIC"; | 2578 case GENERIC: return "GENERIC"; |
2596 default: | 2579 default: |
2597 UNREACHABLE(); | 2580 UNREACHABLE(); |
2598 return NULL; | 2581 return NULL; |
2599 } | 2582 } |
2600 } | 2583 } |
2601 | 2584 |
2602 | 2585 |
2603 CompareIC::State CompareIC::TargetState(State state, | 2586 static CompareIC::State InputState(CompareIC::State old_state, |
| 2587 Handle<Object> value) { |
| 2588 switch (old_state) { |
| 2589 case CompareIC::UNINITIALIZED: |
| 2590 if (value->IsSmi()) return CompareIC::SMI; |
| 2591 if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER; |
| 2592 if (value->IsSymbol()) return CompareIC::SYMBOL; |
| 2593 if (value->IsString()) return CompareIC::STRING; |
| 2594 if (value->IsJSObject()) return CompareIC::OBJECT; |
| 2595 break; |
| 2596 case CompareIC::SMI: |
| 2597 if (value->IsSmi()) return CompareIC::SMI; |
| 2598 if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER; |
| 2599 break; |
| 2600 case CompareIC::HEAP_NUMBER: |
| 2601 if (value->IsNumber()) return CompareIC::HEAP_NUMBER; |
| 2602 break; |
| 2603 case CompareIC::SYMBOL: |
| 2604 if (value->IsSymbol()) return CompareIC::SYMBOL; |
| 2605 if (value->IsString()) return CompareIC::STRING; |
| 2606 break; |
| 2607 case CompareIC::STRING: |
| 2608 if (value->IsSymbol() || value->IsString()) return CompareIC::STRING; |
| 2609 break; |
| 2610 case CompareIC::OBJECT: |
| 2611 if (value->IsJSObject()) return CompareIC::OBJECT; |
| 2612 break; |
| 2613 case CompareIC::GENERIC: |
| 2614 break; |
| 2615 case CompareIC::KNOWN_OBJECTS: |
| 2616 UNREACHABLE(); |
| 2617 break; |
| 2618 } |
| 2619 return CompareIC::GENERIC; |
| 2620 } |
| 2621 |
| 2622 |
| 2623 CompareIC::State CompareIC::TargetState(State old_state, |
| 2624 State old_left, |
| 2625 State old_right, |
2604 bool has_inlined_smi_code, | 2626 bool has_inlined_smi_code, |
2605 Handle<Object> x, | 2627 Handle<Object> x, |
2606 Handle<Object> y) { | 2628 Handle<Object> y) { |
2607 switch (state) { | 2629 switch (old_state) { |
2608 case UNINITIALIZED: | 2630 case UNINITIALIZED: |
2609 if (x->IsSmi() && y->IsSmi()) return SMIS; | 2631 if (x->IsSmi() && y->IsSmi()) return SMI; |
2610 if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS; | 2632 if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBER; |
2611 if (Token::IsOrderedRelationalCompareOp(op_)) { | 2633 if (Token::IsOrderedRelationalCompareOp(op_)) { |
2612 // Ordered comparisons treat undefined as NaN, so the | 2634 // Ordered comparisons treat undefined as NaN, so the |
2613 // HEAP_NUMBER stub will do the right thing. | 2635 // HEAP_NUMBER stub will do the right thing. |
2614 if ((x->IsNumber() && y->IsUndefined()) || | 2636 if ((x->IsNumber() && y->IsUndefined()) || |
2615 (y->IsNumber() && x->IsUndefined())) { | 2637 (y->IsNumber() && x->IsUndefined())) { |
2616 return HEAP_NUMBERS; | 2638 return HEAP_NUMBER; |
2617 } | 2639 } |
2618 } | 2640 } |
2619 if (x->IsSymbol() && y->IsSymbol()) { | 2641 if (x->IsSymbol() && y->IsSymbol()) { |
2620 // We compare symbols as strings if we need to determine | 2642 // We compare symbols as strings if we need to determine |
2621 // the order in a non-equality compare. | 2643 // the order in a non-equality compare. |
2622 return Token::IsEqualityOp(op_) ? SYMBOLS : STRINGS; | 2644 return Token::IsEqualityOp(op_) ? SYMBOL : STRING; |
2623 } | 2645 } |
2624 if (x->IsString() && y->IsString()) return STRINGS; | 2646 if (x->IsString() && y->IsString()) return STRING; |
2625 if (!Token::IsEqualityOp(op_)) return GENERIC; | 2647 if (!Token::IsEqualityOp(op_)) return GENERIC; |
2626 if (x->IsJSObject() && y->IsJSObject()) { | 2648 if (x->IsJSObject() && y->IsJSObject()) { |
2627 if (Handle<JSObject>::cast(x)->map() == | 2649 if (Handle<JSObject>::cast(x)->map() == |
2628 Handle<JSObject>::cast(y)->map() && | 2650 Handle<JSObject>::cast(y)->map() && |
2629 Token::IsEqualityOp(op_)) { | 2651 Token::IsEqualityOp(op_)) { |
2630 return KNOWN_OBJECTS; | 2652 return KNOWN_OBJECTS; |
2631 } else { | 2653 } else { |
2632 return OBJECTS; | 2654 return OBJECT; |
2633 } | 2655 } |
2634 } | 2656 } |
2635 return GENERIC; | 2657 return GENERIC; |
2636 case SMIS: | 2658 case SMI: |
2637 return has_inlined_smi_code && x->IsNumber() && y->IsNumber() | 2659 return has_inlined_smi_code && x->IsNumber() && y->IsNumber() |
2638 ? HEAP_NUMBERS | 2660 ? HEAP_NUMBER |
2639 : GENERIC; | 2661 : GENERIC; |
2640 case SYMBOLS: | 2662 case SYMBOL: |
2641 ASSERT(Token::IsEqualityOp(op_)); | 2663 ASSERT(Token::IsEqualityOp(op_)); |
2642 return x->IsString() && y->IsString() ? STRINGS : GENERIC; | 2664 return x->IsString() && y->IsString() ? STRING : GENERIC; |
2643 case HEAP_NUMBERS: | 2665 case HEAP_NUMBER: |
2644 case STRINGS: | 2666 if (old_left == SMI && x->IsHeapNumber()) return HEAP_NUMBER; |
2645 case OBJECTS: | 2667 if (old_right == SMI && y->IsHeapNumber()) return HEAP_NUMBER; |
| 2668 case STRING: |
| 2669 case OBJECT: |
2646 case KNOWN_OBJECTS: | 2670 case KNOWN_OBJECTS: |
2647 case GENERIC: | 2671 case GENERIC: |
2648 return GENERIC; | 2672 return GENERIC; |
2649 } | 2673 } |
2650 UNREACHABLE(); | 2674 UNREACHABLE(); |
2651 return GENERIC; | 2675 return GENERIC; // Make the compiler happy. |
2652 } | 2676 } |
2653 | 2677 |
2654 | 2678 |
2655 // Used from ic_<arch>.cc. | 2679 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { |
| 2680 HandleScope scope; |
| 2681 State previous_left, previous_right, previous_state; |
| 2682 ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left, |
| 2683 &previous_right, &previous_state, NULL); |
| 2684 State new_left = InputState(previous_left, x); |
| 2685 State new_right = InputState(previous_right, y); |
| 2686 State state = TargetState(previous_state, previous_left, previous_right, |
| 2687 HasInlinedSmiCode(address()), x, y); |
| 2688 ICCompareStub stub(op_, new_left, new_right, state); |
| 2689 if (state == KNOWN_OBJECTS) { |
| 2690 stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); |
| 2691 } |
| 2692 set_target(*stub.GetCode()); |
| 2693 |
| 2694 #ifdef DEBUG |
| 2695 if (FLAG_trace_ic) { |
| 2696 PrintF("[CompareIC (%s->%s)#%s]\n", |
| 2697 GetStateName(previous_state), |
| 2698 GetStateName(state), |
| 2699 Token::Name(op_)); |
| 2700 } |
| 2701 #endif |
| 2702 |
| 2703 // Activate inlined smi code. |
| 2704 if (previous_state == UNINITIALIZED) { |
| 2705 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2706 } |
| 2707 } |
| 2708 |
| 2709 |
| 2710 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. |
2656 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { | 2711 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { |
2657 NoHandleAllocation na; | 2712 NoHandleAllocation na; |
2658 ASSERT(args.length() == 3); | 2713 ASSERT(args.length() == 3); |
2659 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); | 2714 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); |
2660 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); | 2715 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); |
2661 return ic.target(); | 2716 return ic.target(); |
2662 } | 2717 } |
2663 | 2718 |
2664 | 2719 |
2665 RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) { | 2720 RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) { |
(...skipping 28 matching lines...) Expand all Loading... |
2694 #undef ADDR | 2749 #undef ADDR |
2695 }; | 2750 }; |
2696 | 2751 |
2697 | 2752 |
2698 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2753 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2699 return IC_utilities[id]; | 2754 return IC_utilities[id]; |
2700 } | 2755 } |
2701 | 2756 |
2702 | 2757 |
2703 } } // namespace v8::internal | 2758 } } // namespace v8::internal |
OLD | NEW |