// Copyright 2011 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_X64_CODE_STUBS_X64_H_ #define V8_X64_CODE_STUBS_X64_H_ #include "ic-inl.h" #include "type-info.h" namespace v8 { namespace internal { // Compute a transcendental math function natively, or call the // TranscendentalCache runtime function. class TranscendentalCacheStub: public CodeStub { public: enum ArgumentType { TAGGED = 0, UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits }; explicit TranscendentalCacheStub(TranscendentalCache::Type type, ArgumentType argument_type) : type_(type), argument_type_(argument_type) {} void Generate(MacroAssembler* masm); private: TranscendentalCache::Type type_; ArgumentType argument_type_; Major MajorKey() { return TranscendentalCache; } int MinorKey() { return type_ | argument_type_; } Runtime::FunctionId RuntimeFunction(); void GenerateOperation(MacroAssembler* masm); }; class ToBooleanStub: public CodeStub { public: ToBooleanStub() { } void Generate(MacroAssembler* masm); private: Major MajorKey() { return ToBoolean; } int MinorKey() { return 0; } }; class TypeRecordingUnaryOpStub: public CodeStub { public: TypeRecordingUnaryOpStub(Token::Value op, UnaryOverwriteMode mode) : op_(op), mode_(mode), operand_type_(TRUnaryOpIC::UNINITIALIZED), name_(NULL) { } TypeRecordingUnaryOpStub( int key, TRUnaryOpIC::TypeInfo operand_type) : op_(OpBits::decode(key)), mode_(ModeBits::decode(key)), operand_type_(operand_type), name_(NULL) { } private: Token::Value op_; UnaryOverwriteMode mode_; // Operand type information determined at runtime. TRUnaryOpIC::TypeInfo operand_type_; char* name_; const char* GetName(); #ifdef DEBUG void Print() { PrintF("TypeRecordingUnaryOpStub %d (op %s), " "(mode %d, runtime_type_info %s)\n", MinorKey(), Token::String(op_), static_cast(mode_), TRUnaryOpIC::GetName(operand_type_)); } #endif class ModeBits: public BitField {}; class OpBits: public BitField {}; class OperandTypeInfoBits: public BitField {}; Major MajorKey() { return TypeRecordingUnaryOp; } int MinorKey() { return ModeBits::encode(mode_) | OpBits::encode(op_) | OperandTypeInfoBits::encode(operand_type_); } // Note: A lot of the helper functions below will vanish when we use virtual // function instead of switch more often. void Generate(MacroAssembler* masm); void GenerateTypeTransition(MacroAssembler* masm); void GenerateSmiStub(MacroAssembler* masm); void GenerateSmiStubSub(MacroAssembler* masm); void GenerateSmiStubBitNot(MacroAssembler* masm); void GenerateSmiCodeSub(MacroAssembler* masm, NearLabel* non_smi, Label* slow); void GenerateSmiCodeBitNot(MacroAssembler* masm, NearLabel* non_smi); void GenerateHeapNumberStub(MacroAssembler* masm); void GenerateHeapNumberStubSub(MacroAssembler* masm); void GenerateHeapNumberStubBitNot(MacroAssembler* masm); void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow); void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow); void GenerateGenericStub(MacroAssembler* masm); void GenerateGenericStubSub(MacroAssembler* masm); void GenerateGenericStubBitNot(MacroAssembler* masm); void GenerateGenericCodeFallback(MacroAssembler* masm); virtual int GetCodeKind() { return Code::TYPE_RECORDING_UNARY_OP_IC; } virtual InlineCacheState GetICState() { return TRUnaryOpIC::ToState(operand_type_); } virtual void FinishCode(Code* code) { code->set_type_recording_unary_op_type(operand_type_); } }; 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) { ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); } TypeRecordingBinaryOpStub( int key, TRBinaryOpIC::TypeInfo operands_type, TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED) : op_(OpBits::decode(key)), mode_(ModeBits::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_; // 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(mode_), TRBinaryOpIC::GetName(operands_type_)); } #endif // Minor key encoding in 15 bits RRRTTTOOOOOOOMM. class ModeBits: public BitField {}; class OpBits: public BitField {}; class OperandTypeInfoBits: public BitField {}; class ResultTypeInfoBits: public BitField {}; Major MajorKey() { return TypeRecordingBinaryOp; } int MinorKey() { return OpBits::encode(op_) | ModeBits::encode(mode_) | OperandTypeInfoBits::encode(operands_type_) | ResultTypeInfoBits::encode(result_type_); } void Generate(MacroAssembler* masm); void GenerateGeneric(MacroAssembler* masm); void GenerateSmiCode(MacroAssembler* masm, Label* slow, SmiCodeGenerateHeapNumberResults heapnumber_results); void GenerateFloatingPointCode(MacroAssembler* masm, Label* allocation_failure, Label* non_numeric_failure); void GenerateStringAddCode(MacroAssembler* masm); void GenerateCallRuntimeCode(MacroAssembler* masm); 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 GenerateOddballStub(MacroAssembler* masm); void GenerateStringStub(MacroAssembler* masm); void GenerateBothStringStub(MacroAssembler* masm); void GenerateGenericStub(MacroAssembler* masm); void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure); 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; }; class StringHelper : public AllStatic { public: // Generate code for copying characters using a simple loop. This should only // be used in places where the number of characters is small and the // additional setup and checking in GenerateCopyCharactersREP adds too much // overhead. Copying of overlapping regions is not supported. static void GenerateCopyCharacters(MacroAssembler* masm, Register dest, Register src, Register count, bool ascii); // Generate code for copying characters using the rep movs instruction. // Copies rcx characters from rsi to rdi. Copying of overlapping regions is // not supported. static void GenerateCopyCharactersREP(MacroAssembler* masm, Register dest, // Must be rdi. Register src, // Must be rsi. Register count, // Must be rcx. bool ascii); // Probe the symbol table for a two character string. If the string is // not found by probing a jump to the label not_found is performed. This jump // does not guarantee that the string is not in the symbol table. If the // string is found the code falls through with the string in register rax. static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, Register c1, Register c2, Register scratch1, Register scratch2, Register scratch3, Register scratch4, Label* not_found); // Generate string hash. static void GenerateHashInit(MacroAssembler* masm, Register hash, Register character, Register scratch); static void GenerateHashAddCharacter(MacroAssembler* masm, Register hash, Register character, Register scratch); static void GenerateHashGetHash(MacroAssembler* masm, Register hash, Register scratch); private: DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); }; // Flag that indicates how to generate code for the stub StringAddStub. enum StringAddFlags { NO_STRING_ADD_FLAGS = 0, // Omit left string check in stub (left is definitely a string). NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0, // Omit right string check in stub (right is definitely a string). NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1, // Omit both string checks in stub. NO_STRING_CHECK_IN_STUB = NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB }; class StringAddStub: public CodeStub { public: explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} private: Major MajorKey() { return StringAdd; } int MinorKey() { return flags_; } void Generate(MacroAssembler* masm); void GenerateConvertArgument(MacroAssembler* masm, int stack_offset, Register arg, Register scratch1, Register scratch2, Register scratch3, Label* slow); const StringAddFlags flags_; }; class SubStringStub: public CodeStub { public: SubStringStub() {} private: Major MajorKey() { return SubString; } int MinorKey() { return 0; } void Generate(MacroAssembler* masm); }; class StringCompareStub: public CodeStub { public: explicit StringCompareStub() {} // Compare two flat ascii strings and returns result in rax after popping two // arguments from 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); }; 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, bool object_is_smi, Label* not_found); private: static void GenerateConvertHashCodeToIndex(MacroAssembler* masm, Register hash, Register mask); 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 }; } } // namespace v8::internal #endif // V8_X64_CODE_STUBS_X64_H_