Index: src/mips/code-stubs-mips.h |
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..675730a5534f9ce96c41eee96aa4d1849f21f384 |
--- /dev/null |
+++ b/src/mips/code-stubs-mips.h |
@@ -0,0 +1,511 @@ |
+// Copyright 2010 the V8 project authors. All rights reserved. |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following |
+// disclaimer in the documentation and/or other materials provided |
+// with the distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived |
+// from this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+#ifndef V8_MIPS_CODE_STUBS_ARM_H_ |
+#define V8_MIPS_CODE_STUBS_ARM_H_ |
+ |
+#include "ic-inl.h" |
+ |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+ |
+// Compute a transcendental math function natively, or call the |
+// TranscendentalCache runtime function. |
+class TranscendentalCacheStub: public CodeStub { |
+ public: |
+ explicit TranscendentalCacheStub(TranscendentalCache::Type type) |
+ : type_(type) {} |
+ void Generate(MacroAssembler* masm); |
+ private: |
+ TranscendentalCache::Type type_; |
+ Major MajorKey() { return TranscendentalCache; } |
+ int MinorKey() { return type_; } |
+ Runtime::FunctionId RuntimeFunction(); |
+}; |
+ |
+ |
+class ToBooleanStub: public CodeStub { |
+ public: |
+ explicit ToBooleanStub(Register tos) : tos_(tos) { } |
+ |
+ void Generate(MacroAssembler* masm); |
+ |
+ private: |
+ Register tos_; |
+ Major MajorKey() { return ToBoolean; } |
+ int MinorKey() { return tos_.code(); } |
+}; |
+ |
+ |
+class GenericBinaryOpStub : public CodeStub { |
+ public: |
+ static const int kUnknownIntValue = -1; |
+ |
+ GenericBinaryOpStub(Token::Value op, |
+ OverwriteMode mode, |
+ Register lhs, |
+ Register rhs, |
+ int constant_rhs = kUnknownIntValue) |
+ : op_(op), |
+ mode_(mode), |
+ lhs_(lhs), |
+ rhs_(rhs), |
+ constant_rhs_(constant_rhs), |
+ specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), |
+ runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI), |
+ name_(NULL) { } |
+ |
+ GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) |
+ : op_(OpBits::decode(key)), |
+ mode_(ModeBits::decode(key)), |
+ lhs_(LhsRegister(RegisterBits::decode(key))), |
+ rhs_(RhsRegister(RegisterBits::decode(key))), |
+ constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))), |
+ specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)), |
+ runtime_operands_type_(type_info), |
+ name_(NULL) { } |
+ |
+ private: |
+ Token::Value op_; |
+ OverwriteMode mode_; |
+ Register lhs_; |
+ Register rhs_; |
+ int constant_rhs_; |
+ bool specialized_on_rhs_; |
+ BinaryOpIC::TypeInfo runtime_operands_type_; |
+ char* name_; |
+ |
+ static const int kMaxKnownRhs = 0x40000000; |
+ static const int kKnownRhsKeyBits = 6; |
+ |
+ // Minor key encoding in 16 bits. |
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {}; |
+ class OpBits: public BitField<Token::Value, 2, 6> {}; |
+ class TypeInfoBits: public BitField<int, 8, 3> {}; |
+ class RegisterBits: public BitField<bool, 11, 1> {}; |
+ class KnownIntBits: public BitField<int, 12, kKnownRhsKeyBits> {}; |
+ |
+ Major MajorKey() { return GenericBinaryOp; } |
+ int MinorKey() { |
+ ASSERT((lhs_.is(a0) && rhs_.is(a1)) || |
+ (lhs_.is(a1) && rhs_.is(a0))); |
+ // Encode the parameters in a unique 16 bit value. |
+ return OpBits::encode(op_) |
+ | ModeBits::encode(mode_) |
+ | KnownIntBits::encode(MinorKeyForKnownInt()) |
+ | TypeInfoBits::encode(runtime_operands_type_) |
+ | RegisterBits::encode(lhs_.is(a0)); |
+ } |
+ |
+ void Generate(MacroAssembler* masm); |
+ void HandleNonSmiBitwiseOp(MacroAssembler* masm, |
+ Register lhs, |
+ Register rhs); |
+ void HandleBinaryOpSlowCases(MacroAssembler* masm, |
+ Label* not_smi, |
+ Register lhs, |
+ Register rhs, |
+ const Builtins::JavaScript& builtin); |
+ void GenerateTypeTransition(MacroAssembler* masm); |
+ |
+ static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) { |
+ if (constant_rhs == kUnknownIntValue) return false; |
+ if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3; |
+ if (op == Token::MOD) { |
+ if (constant_rhs <= 1) return false; |
+ if (constant_rhs <= 10) return true; |
+ if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true; |
+ return false; |
+ } |
+ return false; |
+ } |
+ |
+ int MinorKeyForKnownInt() { |
+ if (!specialized_on_rhs_) return 0; |
+ if (constant_rhs_ <= 10) return constant_rhs_ + 1; |
+ ASSERT(IsPowerOf2(constant_rhs_)); |
+ int key = 12; |
+ int d = constant_rhs_; |
+ while ((d & 1) == 0) { |
+ key++; |
+ d >>= 1; |
+ } |
+ ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits)); |
+ return key; |
+ } |
+ |
+ int KnownBitsForMinorKey(int key) { |
+ if (!key) return 0; |
+ if (key <= 11) return key - 1; |
+ int d = 1; |
+ while (key != 12) { |
+ key--; |
+ d <<= 1; |
+ } |
+ return d; |
+ } |
+ |
+ Register LhsRegister(bool lhs_is_a0) { |
+ return lhs_is_a0 ? a0 : a1; |
+ } |
+ |
+ Register RhsRegister(bool lhs_is_a0) { |
+ return lhs_is_a0 ? a1 : a0; |
+ } |
+ |
+ bool HasSmiSmiFastPath() { |
+ return op_ != Token::DIV; |
+ } |
+ |
+ bool ShouldGenerateSmiCode() { |
+ return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) && |
+ runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && |
+ runtime_operands_type_ != BinaryOpIC::STRINGS; |
+ } |
+ |
+ bool ShouldGenerateFPCode() { |
+ return runtime_operands_type_ != BinaryOpIC::STRINGS; |
+ } |
+ |
+ virtual int GetCodeKind() { return Code::BINARY_OP_IC; } |
+ |
+ virtual InlineCacheState GetICState() { |
+ return BinaryOpIC::ToState(runtime_operands_type_); |
+ } |
+ |
+ const char* GetName(); |
+ |
+ virtual void FinishCode(Code* code) { |
+ code->set_binary_op_type(runtime_operands_type_); |
+ } |
+ |
+#ifdef DEBUG |
+ void Print() { |
+ if (!specialized_on_rhs_) { |
+ PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); |
+ } else { |
+ PrintF("GenericBinaryOpStub (%s by %d)\n", |
+ Token::String(op_), |
+ constant_rhs_); |
+ } |
+ } |
+#endif |
+}; |
+ |
+class TypeRecordingBinaryOpStub: public CodeStub { |
+ public: |
+ TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) |
+ : op_(op), |
+ mode_(mode), |
+ operands_type_(TRBinaryOpIC::UNINITIALIZED), |
+ result_type_(TRBinaryOpIC::UNINITIALIZED), |
+ name_(NULL) { |
+ UNIMPLEMENTED_MIPS(); |
+ } |
+ |
+ TypeRecordingBinaryOpStub( |
+ int key, |
+ TRBinaryOpIC::TypeInfo operands_type, |
+ TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED) |
+ : op_(OpBits::decode(key)), |
+ mode_(ModeBits::decode(key)), |
+ use_fpu_(FPUBits::decode(key)), |
+ operands_type_(operands_type), |
+ result_type_(result_type), |
+ name_(NULL) { } |
+ |
+ private: |
+ enum SmiCodeGenerateHeapNumberResults { |
+ ALLOW_HEAPNUMBER_RESULTS, |
+ NO_HEAPNUMBER_RESULTS |
+ }; |
+ |
+ Token::Value op_; |
+ OverwriteMode mode_; |
+ bool use_fpu_; |
+ |
+ // Operand type information determined at runtime. |
+ TRBinaryOpIC::TypeInfo operands_type_; |
+ TRBinaryOpIC::TypeInfo result_type_; |
+ |
+ char* name_; |
+ |
+ const char* GetName(); |
+ |
+#ifdef DEBUG |
+ void Print() { |
+ PrintF("TypeRecordingBinaryOpStub %d (op %s), " |
+ "(mode %d, runtime_type_info %s)\n", |
+ MinorKey(), |
+ Token::String(op_), |
+ static_cast<int>(mode_), |
+ TRBinaryOpIC::GetName(operands_type_)); |
+ } |
+#endif |
+ |
+ // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM. |
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {}; |
+ class OpBits: public BitField<Token::Value, 2, 7> {}; |
+ class FPUBits: public BitField<bool, 9, 1> {}; |
+ class OperandTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 10, 3> {}; |
+ class ResultTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 13, 3> {}; |
+ |
+ Major MajorKey() { return TypeRecordingBinaryOp; } |
+ int MinorKey() { |
+ return OpBits::encode(op_) |
+ | ModeBits::encode(mode_) |
+ | FPUBits::encode(use_fpu_) |
+ | OperandTypeInfoBits::encode(operands_type_) |
+ | ResultTypeInfoBits::encode(result_type_); |
+ } |
+ |
+ void Generate(MacroAssembler* masm); |
+ void GenerateGeneric(MacroAssembler* masm); |
+ void GenerateSmiSmiOperation(MacroAssembler* masm); |
+ void GenerateFPOperation(MacroAssembler* masm, |
+ bool smi_operands, |
+ Label* not_numbers, |
+ Label* gc_required); |
+ void GenerateSmiCode(MacroAssembler* masm, |
+ Label* gc_required, |
+ SmiCodeGenerateHeapNumberResults heapnumber_results); |
+ void GenerateLoadArguments(MacroAssembler* masm); |
+ void GenerateReturn(MacroAssembler* masm); |
+ void GenerateUninitializedStub(MacroAssembler* masm); |
+ void GenerateSmiStub(MacroAssembler* masm); |
+ void GenerateInt32Stub(MacroAssembler* masm); |
+ void GenerateHeapNumberStub(MacroAssembler* masm); |
+ void GenerateStringStub(MacroAssembler* masm); |
+ void GenerateGenericStub(MacroAssembler* masm); |
+ void GenerateAddStrings(MacroAssembler* masm); |
+ void GenerateCallRuntime(MacroAssembler* masm); |
+ |
+ void GenerateHeapResultAllocation(MacroAssembler* masm, |
+ Register result, |
+ Register heap_number_map, |
+ Register scratch1, |
+ Register scratch2, |
+ Label* gc_required); |
+ void GenerateRegisterArgsPush(MacroAssembler* masm); |
+ void GenerateTypeTransition(MacroAssembler* masm); |
+ void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); |
+ |
+ virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; } |
+ |
+ virtual InlineCacheState GetICState() { |
+ return TRBinaryOpIC::ToState(operands_type_); |
+ } |
+ |
+ virtual void FinishCode(Code* code) { |
+ code->set_type_recording_binary_op_type(operands_type_); |
+ code->set_type_recording_binary_op_result_type(result_type_); |
+ } |
+ |
+ friend class CodeGenerator; |
+}; |
+ |
+ |
+// Flag that indicates how to generate code for the stub StringAddStub. |
+enum StringAddFlags { |
+ NO_STRING_ADD_FLAGS = 0, |
+ NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. |
+}; |
+ |
+ |
+class StringAddStub: public CodeStub { |
+ public: |
+ explicit StringAddStub(StringAddFlags flags) { |
+ string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); |
+ } |
+ |
+ private: |
+ Major MajorKey() { return StringAdd; } |
+ int MinorKey() { return string_check_ ? 0 : 1; } |
+ |
+ void Generate(MacroAssembler* masm); |
+ |
+ // Should the stub check whether arguments are strings? |
+ bool string_check_; |
+}; |
+ |
+ |
+class SubStringStub: public CodeStub { |
+ public: |
+ SubStringStub() {} |
+ |
+ private: |
+ Major MajorKey() { return SubString; } |
+ int MinorKey() { return 0; } |
+ |
+ void Generate(MacroAssembler* masm); |
+}; |
+ |
+ |
+class StringCompareStub: public CodeStub { |
+ public: |
+ StringCompareStub() { } |
+ |
+ // Compare two flat ASCII strings and returns result in v0. |
+ // Does not use the stack. |
+ static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
+ Register left, |
+ Register right, |
+ Register scratch1, |
+ Register scratch2, |
+ Register scratch3, |
+ Register scratch4); |
+ |
+ private: |
+ Major MajorKey() { return StringCompare; } |
+ int MinorKey() { return 0; } |
+ |
+ void Generate(MacroAssembler* masm); |
+}; |
+ |
+ |
+// This stub can convert a signed int32 to a heap number (double). It does |
+// not work for int32s that are in Smi range! No GC occurs during this stub |
+// so you don't have to set up the frame. |
+class WriteInt32ToHeapNumberStub : public CodeStub { |
+ public: |
+ WriteInt32ToHeapNumberStub(Register the_int, |
+ Register the_heap_number, |
+ Register scratch, |
+ Register scratch2) |
+ : the_int_(the_int), |
+ the_heap_number_(the_heap_number), |
+ scratch_(scratch), |
+ sign_(scratch2) { } |
+ |
+ private: |
+ Register the_int_; |
+ Register the_heap_number_; |
+ Register scratch_; |
+ Register sign_; |
+ |
+ // Minor key encoding in 16 bits. |
+ class IntRegisterBits: public BitField<int, 0, 4> {}; |
+ class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; |
+ class ScratchRegisterBits: public BitField<int, 8, 4> {}; |
+ |
+ Major MajorKey() { return WriteInt32ToHeapNumber; } |
+ int MinorKey() { |
+ // Encode the parameters in a unique 16 bit value. |
+ return IntRegisterBits::encode(the_int_.code()) |
+ | HeapNumberRegisterBits::encode(the_heap_number_.code()) |
+ | ScratchRegisterBits::encode(scratch_.code()); |
+ } |
+ |
+ void Generate(MacroAssembler* masm); |
+ |
+ const char* GetName() { return "WriteInt32ToHeapNumberStub"; } |
+ |
+#ifdef DEBUG |
+ void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); } |
+#endif |
+}; |
+ |
+ |
+class NumberToStringStub: public CodeStub { |
+ public: |
+ NumberToStringStub() { } |
+ |
+ // Generate code to do a lookup in the number string cache. If the number in |
+ // the register object is found in the cache the generated code falls through |
+ // with the result in the result register. The object and the result register |
+ // can be the same. If the number is not found in the cache the code jumps to |
+ // the label not_found with only the content of register object unchanged. |
+ static void GenerateLookupNumberStringCache(MacroAssembler* masm, |
+ Register object, |
+ Register result, |
+ Register scratch1, |
+ Register scratch2, |
+ Register scratch3, |
+ bool object_is_smi, |
+ Label* not_found); |
+ |
+ private: |
+ Major MajorKey() { return NumberToString; } |
+ int MinorKey() { return 0; } |
+ |
+ void Generate(MacroAssembler* masm); |
+ |
+ const char* GetName() { return "NumberToStringStub"; } |
+ |
+#ifdef DEBUG |
+ void Print() { |
+ PrintF("NumberToStringStub\n"); |
+ } |
+#endif |
+}; |
+ |
+ |
+// Enter C code from generated RegExp code in a way that allows |
+// the C code to fix the return address in case of a GC. |
+// Currently only needed on ARM and MIPS. |
+class RegExpCEntryStub: public CodeStub { |
+ public: |
+ RegExpCEntryStub() {} |
+ virtual ~RegExpCEntryStub() {} |
+ void Generate(MacroAssembler* masm); |
+ |
+ private: |
+ Major MajorKey() { return RegExpCEntry; } |
+ int MinorKey() { return 0; } |
+ |
+ bool NeedsImmovableCode() { return true; } |
+ |
+ const char* GetName() { return "RegExpCEntryStub"; } |
+}; |
+ |
+ |
+// Generate code the to load an element from a pixel array. The receiver is |
+// assumed to not be a smi and to have elements, the caller must guarantee this |
+// precondition. If the receiver does not have elements that are pixel arrays, |
+// the generated code jumps to not_pixel_array. If key is not a smi, then the |
+// generated code branches to key_not_smi. Callers can specify NULL for |
+// key_not_smi to signal that a smi check has already been performed on key so |
+// that the smi check is not generated . If key is not a valid index within the |
+// bounds of the pixel array, the generated code jumps to out_of_range. |
+void GenerateFastPixelArrayLoad(MacroAssembler* masm, |
+ Register receiver, |
+ Register key, |
+ Register elements_map, |
+ Register elements, |
+ Register scratch1, |
+ Register scratch2, |
+ Register result, |
+ Label* not_pixel_array, |
+ Label* key_not_smi, |
+ Label* out_of_range); |
+ |
+ |
+} } // namespace v8::internal |
+ |
+#endif // V8_MIPS_CODE_STUBS_ARM_H_ |