| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "compiler.h" | 32 #include "compiler.h" |
| 33 #include "debug.h" | 33 #include "debug.h" |
| 34 #include "ic-inl.h" | 34 #include "ic-inl.h" |
| 35 #include "parser.h" | 35 #include "parser.h" |
| 36 #include "regexp-macro-assembler.h" | 36 #include "regexp-macro-assembler.h" |
| 37 #include "register-allocator-inl.h" | 37 #include "register-allocator-inl.h" |
| 38 #include "scopes.h" | 38 #include "scopes.h" |
| 39 #include "virtual-frame-inl.h" |
| 39 | 40 |
| 40 namespace v8 { | 41 namespace v8 { |
| 41 namespace internal { | 42 namespace internal { |
| 42 | 43 |
| 43 #define __ ACCESS_MASM(masm_) | 44 #define __ ACCESS_MASM(masm_) |
| 44 | 45 |
| 45 // ------------------------------------------------------------------------- | 46 // ------------------------------------------------------------------------- |
| 46 // Platform-specific DeferredCode functions. | 47 // Platform-specific DeferredCode functions. |
| 47 | 48 |
| 48 void DeferredCode::SaveRegisters() { | 49 void DeferredCode::SaveRegisters() { |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 info_(NULL), | 253 info_(NULL), |
| 253 frame_(NULL), | 254 frame_(NULL), |
| 254 allocator_(NULL), | 255 allocator_(NULL), |
| 255 state_(NULL), | 256 state_(NULL), |
| 256 loop_nesting_(0), | 257 loop_nesting_(0), |
| 257 function_return_is_shadowed_(false), | 258 function_return_is_shadowed_(false), |
| 258 in_spilled_code_(false) { | 259 in_spilled_code_(false) { |
| 259 } | 260 } |
| 260 | 261 |
| 261 | 262 |
| 262 Scope* CodeGenerator::scope() { return info_->function()->scope(); } | |
| 263 | |
| 264 | |
| 265 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 263 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 266 // Call the runtime to declare the globals. The inevitable call | 264 // Call the runtime to declare the globals. The inevitable call |
| 267 // will sync frame elements to memory anyway, so we do it eagerly to | 265 // will sync frame elements to memory anyway, so we do it eagerly to |
| 268 // allow us to push the arguments directly into place. | 266 // allow us to push the arguments directly into place. |
| 269 frame_->SyncRange(0, frame_->element_count() - 1); | 267 frame_->SyncRange(0, frame_->element_count() - 1); |
| 270 | 268 |
| 271 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); | 269 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); |
| 272 frame_->EmitPush(rsi); // The context is the first argument. | 270 frame_->EmitPush(rsi); // The context is the first argument. |
| 273 frame_->EmitPush(kScratchRegister); | 271 frame_->EmitPush(kScratchRegister); |
| 274 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); | 272 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); |
| 275 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 273 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 276 // Return value is ignored. | 274 // Return value is ignored. |
| 277 } | 275 } |
| 278 | 276 |
| 279 | 277 |
| 280 void CodeGenerator::Generate(CompilationInfo* info) { | 278 void CodeGenerator::Generate(CompilationInfo* info) { |
| 281 // Record the position for debugging purposes. | 279 // Record the position for debugging purposes. |
| 282 CodeForFunctionPosition(info->function()); | 280 CodeForFunctionPosition(info->function()); |
| 281 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); |
| 283 | 282 |
| 284 // Initialize state. | 283 // Initialize state. |
| 285 info_ = info; | 284 info_ = info; |
| 286 ASSERT(allocator_ == NULL); | 285 ASSERT(allocator_ == NULL); |
| 287 RegisterAllocator register_allocator(this); | 286 RegisterAllocator register_allocator(this); |
| 288 allocator_ = ®ister_allocator; | 287 allocator_ = ®ister_allocator; |
| 289 ASSERT(frame_ == NULL); | 288 ASSERT(frame_ == NULL); |
| 290 frame_ = new VirtualFrame(); | 289 frame_ = new VirtualFrame(); |
| 291 set_in_spilled_code(false); | 290 set_in_spilled_code(false); |
| 292 | 291 |
| (...skipping 3578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3871 __ bind(&slow_case); | 3870 __ bind(&slow_case); |
| 3872 // Move the undefined value into the result register, which will | 3871 // Move the undefined value into the result register, which will |
| 3873 // trigger the slow case. | 3872 // trigger the slow case. |
| 3874 __ LoadRoot(temp.reg(), Heap::kUndefinedValueRootIndex); | 3873 __ LoadRoot(temp.reg(), Heap::kUndefinedValueRootIndex); |
| 3875 | 3874 |
| 3876 __ bind(&end); | 3875 __ bind(&end); |
| 3877 frame_->Push(&temp); | 3876 frame_->Push(&temp); |
| 3878 } | 3877 } |
| 3879 | 3878 |
| 3880 | 3879 |
| 3880 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { |
| 3881 Comment(masm_, "[ GenerateCharFromCode"); |
| 3882 ASSERT(args->length() == 1); |
| 3883 |
| 3884 Load(args->at(0)); |
| 3885 Result code = frame_->Pop(); |
| 3886 code.ToRegister(); |
| 3887 ASSERT(code.is_valid()); |
| 3888 |
| 3889 Result temp = allocator()->Allocate(); |
| 3890 ASSERT(temp.is_valid()); |
| 3891 |
| 3892 JumpTarget slow_case; |
| 3893 JumpTarget exit; |
| 3894 |
| 3895 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 3896 Condition is_smi = __ CheckSmi(code.reg()); |
| 3897 slow_case.Branch(NegateCondition(is_smi), &code, not_taken); |
| 3898 |
| 3899 __ SmiToInteger32(kScratchRegister, code.reg()); |
| 3900 __ cmpl(kScratchRegister, Immediate(String::kMaxAsciiCharCode)); |
| 3901 slow_case.Branch(above, &code, not_taken); |
| 3902 |
| 3903 __ Move(temp.reg(), Factory::single_character_string_cache()); |
| 3904 __ movq(temp.reg(), FieldOperand(temp.reg(), |
| 3905 kScratchRegister, times_pointer_size, |
| 3906 FixedArray::kHeaderSize)); |
| 3907 __ CompareRoot(temp.reg(), Heap::kUndefinedValueRootIndex); |
| 3908 slow_case.Branch(equal, &code, not_taken); |
| 3909 code.Unuse(); |
| 3910 |
| 3911 frame_->Push(&temp); |
| 3912 exit.Jump(); |
| 3913 |
| 3914 slow_case.Bind(&code); |
| 3915 frame_->Push(&code); |
| 3916 Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1); |
| 3917 frame_->Push(&result); |
| 3918 |
| 3919 exit.Bind(); |
| 3920 } |
| 3921 |
| 3922 |
| 3881 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3923 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3882 ASSERT(args->length() == 1); | 3924 ASSERT(args->length() == 1); |
| 3883 Load(args->at(0)); | 3925 Load(args->at(0)); |
| 3884 Result value = frame_->Pop(); | 3926 Result value = frame_->Pop(); |
| 3885 value.ToRegister(); | 3927 value.ToRegister(); |
| 3886 ASSERT(value.is_valid()); | 3928 ASSERT(value.is_valid()); |
| 3887 Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); | 3929 Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); |
| 3888 value.Unuse(); | 3930 value.Unuse(); |
| 3889 destination()->Split(positive_smi); | 3931 destination()->Split(positive_smi); |
| 3890 } | 3932 } |
| 3891 | 3933 |
| 3892 | 3934 |
| 3935 // Generates the Math.pow method - currently just calls runtime. |
| 3936 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
| 3937 ASSERT(args->length() == 2); |
| 3938 Load(args->at(0)); |
| 3939 Load(args->at(1)); |
| 3940 Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); |
| 3941 frame_->Push(&res); |
| 3942 } |
| 3943 |
| 3944 |
| 3945 // Generates the Math.sqrt method - currently just calls runtime. |
| 3946 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 3947 ASSERT(args->length() == 1); |
| 3948 Load(args->at(0)); |
| 3949 Result res = frame_->CallRuntime(Runtime::kMath_sqrt, 1); |
| 3950 frame_->Push(&res); |
| 3951 } |
| 3952 |
| 3953 |
| 3893 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3954 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 3894 ASSERT(args->length() == 1); | 3955 ASSERT(args->length() == 1); |
| 3895 Load(args->at(0)); | 3956 Load(args->at(0)); |
| 3896 Result value = frame_->Pop(); | 3957 Result value = frame_->Pop(); |
| 3897 value.ToRegister(); | 3958 value.ToRegister(); |
| 3898 ASSERT(value.is_valid()); | 3959 ASSERT(value.is_valid()); |
| 3899 Condition is_smi = masm_->CheckSmi(value.reg()); | 3960 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 3900 value.Unuse(); | 3961 value.Unuse(); |
| 3901 destination()->Split(is_smi); | 3962 destination()->Split(is_smi); |
| 3902 } | 3963 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3950 __ movq(rbp_as_smi.reg(), rbp); | 4011 __ movq(rbp_as_smi.reg(), rbp); |
| 3951 frame_->Push(&rbp_as_smi); | 4012 frame_->Push(&rbp_as_smi); |
| 3952 } | 4013 } |
| 3953 | 4014 |
| 3954 | 4015 |
| 3955 void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { | 4016 void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { |
| 3956 ASSERT(args->length() == 0); | 4017 ASSERT(args->length() == 0); |
| 3957 frame_->SpillAll(); | 4018 frame_->SpillAll(); |
| 3958 __ push(rsi); | 4019 __ push(rsi); |
| 3959 | 4020 |
| 3960 // Make sure the frame is aligned like the OS expects. | 4021 static const int num_arguments = 0; |
| 3961 static const int kFrameAlignment = OS::ActivationFrameAlignment(); | 4022 __ PrepareCallCFunction(num_arguments); |
| 3962 if (kFrameAlignment > 0) { | |
| 3963 ASSERT(IsPowerOf2(kFrameAlignment)); | |
| 3964 __ movq(rbx, rsp); // Save in AMD-64 abi callee-saved register. | |
| 3965 __ and_(rsp, Immediate(-kFrameAlignment)); | |
| 3966 } | |
| 3967 | 4023 |
| 3968 // Call V8::RandomPositiveSmi(). | 4024 // Call V8::RandomPositiveSmi(). |
| 3969 __ Call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY); | 4025 __ CallCFunction(ExternalReference::random_positive_smi_function(), |
| 3970 | 4026 num_arguments); |
| 3971 // Restore stack pointer from callee-saved register. | |
| 3972 if (kFrameAlignment > 0) { | |
| 3973 __ movq(rsp, rbx); | |
| 3974 } | |
| 3975 | 4027 |
| 3976 __ pop(rsi); | 4028 __ pop(rsi); |
| 3977 Result result = allocator_->Allocate(rax); | 4029 Result result = allocator_->Allocate(rax); |
| 3978 frame_->Push(&result); | 4030 frame_->Push(&result); |
| 3979 } | 4031 } |
| 3980 | 4032 |
| 3981 | 4033 |
| 3982 void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { | 4034 void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { |
| 3983 ASSERT_EQ(args->length(), 4); | 4035 ASSERT_EQ(args->length(), 4); |
| 3984 | 4036 |
| (...skipping 1245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5230 right.is_constant() && !right.handle()->IsSmi(); | 5282 right.is_constant() && !right.handle()->IsSmi(); |
| 5231 | 5283 |
| 5232 if (left_is_smi_constant && right_is_smi_constant) { | 5284 if (left_is_smi_constant && right_is_smi_constant) { |
| 5233 // Compute the constant result at compile time, and leave it on the frame. | 5285 // Compute the constant result at compile time, and leave it on the frame. |
| 5234 int left_int = Smi::cast(*left.handle())->value(); | 5286 int left_int = Smi::cast(*left.handle())->value(); |
| 5235 int right_int = Smi::cast(*right.handle())->value(); | 5287 int right_int = Smi::cast(*right.handle())->value(); |
| 5236 if (FoldConstantSmis(op, left_int, right_int)) return; | 5288 if (FoldConstantSmis(op, left_int, right_int)) return; |
| 5237 } | 5289 } |
| 5238 | 5290 |
| 5239 // Get number type of left and right sub-expressions. | 5291 // Get number type of left and right sub-expressions. |
| 5240 NumberInfo::Type operands_type = | 5292 NumberInfo operands_type = |
| 5241 NumberInfo::Combine(left.number_info(), right.number_info()); | 5293 NumberInfo::Combine(left.number_info(), right.number_info()); |
| 5242 | 5294 |
| 5243 Result answer; | 5295 Result answer; |
| 5244 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 5296 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
| 5245 GenericBinaryOpStub stub(op, | 5297 GenericBinaryOpStub stub(op, |
| 5246 overwrite_mode, | 5298 overwrite_mode, |
| 5247 NO_SMI_CODE_IN_STUB, | 5299 NO_SMI_CODE_IN_STUB, |
| 5248 operands_type); | 5300 operands_type); |
| 5249 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 5301 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 5250 } else if (right_is_smi_constant) { | 5302 } else if (right_is_smi_constant) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 5266 overwrite_mode, | 5318 overwrite_mode, |
| 5267 NO_GENERIC_BINARY_FLAGS, | 5319 NO_GENERIC_BINARY_FLAGS, |
| 5268 operands_type); | 5320 operands_type); |
| 5269 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 5321 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 5270 } | 5322 } |
| 5271 } | 5323 } |
| 5272 | 5324 |
| 5273 // Set NumberInfo of result according to the operation performed. | 5325 // Set NumberInfo of result according to the operation performed. |
| 5274 // We rely on the fact that smis have a 32 bit payload on x64. | 5326 // We rely on the fact that smis have a 32 bit payload on x64. |
| 5275 ASSERT(kSmiValueSize == 32); | 5327 ASSERT(kSmiValueSize == 32); |
| 5276 NumberInfo::Type result_type = NumberInfo::kUnknown; | 5328 NumberInfo result_type = NumberInfo::Unknown(); |
| 5277 switch (op) { | 5329 switch (op) { |
| 5278 case Token::COMMA: | 5330 case Token::COMMA: |
| 5279 result_type = right.number_info(); | 5331 result_type = right.number_info(); |
| 5280 break; | 5332 break; |
| 5281 case Token::OR: | 5333 case Token::OR: |
| 5282 case Token::AND: | 5334 case Token::AND: |
| 5283 // Result type can be either of the two input types. | 5335 // Result type can be either of the two input types. |
| 5284 result_type = operands_type; | 5336 result_type = operands_type; |
| 5285 break; | 5337 break; |
| 5286 case Token::BIT_OR: | 5338 case Token::BIT_OR: |
| 5287 case Token::BIT_XOR: | 5339 case Token::BIT_XOR: |
| 5288 case Token::BIT_AND: | 5340 case Token::BIT_AND: |
| 5289 // Result is always a smi. | 5341 // Result is always a smi. |
| 5290 result_type = NumberInfo::kSmi; | 5342 result_type = NumberInfo::Smi(); |
| 5291 break; | 5343 break; |
| 5292 case Token::SAR: | 5344 case Token::SAR: |
| 5293 case Token::SHL: | 5345 case Token::SHL: |
| 5294 // Result is always a smi. | 5346 // Result is always a smi. |
| 5295 result_type = NumberInfo::kSmi; | 5347 result_type = NumberInfo::Smi(); |
| 5296 break; | 5348 break; |
| 5297 case Token::SHR: | 5349 case Token::SHR: |
| 5298 // Result of x >>> y is always a smi if y >= 1, otherwise a number. | 5350 // Result of x >>> y is always a smi if y >= 1, otherwise a number. |
| 5299 result_type = (right.is_constant() && right.handle()->IsSmi() | 5351 result_type = (right.is_constant() && right.handle()->IsSmi() |
| 5300 && Smi::cast(*right.handle())->value() >= 1) | 5352 && Smi::cast(*right.handle())->value() >= 1) |
| 5301 ? NumberInfo::kSmi | 5353 ? NumberInfo::Smi() |
| 5302 : NumberInfo::kNumber; | 5354 : NumberInfo::Number(); |
| 5303 break; | 5355 break; |
| 5304 case Token::ADD: | 5356 case Token::ADD: |
| 5305 // Result could be a string or a number. Check types of inputs. | 5357 // Result could be a string or a number. Check types of inputs. |
| 5306 result_type = NumberInfo::IsNumber(operands_type) | 5358 result_type = operands_type.IsNumber() |
| 5307 ? NumberInfo::kNumber | 5359 ? NumberInfo::Number() |
| 5308 : NumberInfo::kUnknown; | 5360 : NumberInfo::Unknown(); |
| 5309 break; | 5361 break; |
| 5310 case Token::SUB: | 5362 case Token::SUB: |
| 5311 case Token::MUL: | 5363 case Token::MUL: |
| 5312 case Token::DIV: | 5364 case Token::DIV: |
| 5313 case Token::MOD: | 5365 case Token::MOD: |
| 5314 // Result is always a number. | 5366 // Result is always a number. |
| 5315 result_type = NumberInfo::kNumber; | 5367 result_type = NumberInfo::Number(); |
| 5316 break; | 5368 break; |
| 5317 default: | 5369 default: |
| 5318 UNREACHABLE(); | 5370 UNREACHABLE(); |
| 5319 } | 5371 } |
| 5320 answer.set_number_info(result_type); | 5372 answer.set_number_info(result_type); |
| 5321 frame_->Push(&answer); | 5373 frame_->Push(&answer); |
| 5322 } | 5374 } |
| 5323 | 5375 |
| 5324 | 5376 |
| 5325 // Emit a LoadIC call to get the value from receiver and leave it in | 5377 // Emit a LoadIC call to get the value from receiver and leave it in |
| (...skipping 1011 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6337 // Return and remove the on-stack parameter. | 6389 // Return and remove the on-stack parameter. |
| 6338 __ ret(1 * kPointerSize); | 6390 __ ret(1 * kPointerSize); |
| 6339 | 6391 |
| 6340 // Create a new closure through the slower runtime call. | 6392 // Create a new closure through the slower runtime call. |
| 6341 __ bind(&gc); | 6393 __ bind(&gc); |
| 6342 __ pop(rcx); // Temporarily remove return address. | 6394 __ pop(rcx); // Temporarily remove return address. |
| 6343 __ pop(rdx); | 6395 __ pop(rdx); |
| 6344 __ push(rsi); | 6396 __ push(rsi); |
| 6345 __ push(rdx); | 6397 __ push(rdx); |
| 6346 __ push(rcx); // Restore return address. | 6398 __ push(rcx); // Restore return address. |
| 6347 __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1); | 6399 __ TailCallRuntime(Runtime::kNewClosure, 2, 1); |
| 6348 } | 6400 } |
| 6349 | 6401 |
| 6350 | 6402 |
| 6351 void FastNewContextStub::Generate(MacroAssembler* masm) { | 6403 void FastNewContextStub::Generate(MacroAssembler* masm) { |
| 6352 // Try to allocate the context in new space. | 6404 // Try to allocate the context in new space. |
| 6353 Label gc; | 6405 Label gc; |
| 6354 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 6406 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 6355 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, | 6407 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, |
| 6356 rax, rbx, rcx, &gc, TAG_OBJECT); | 6408 rax, rbx, rcx, &gc, TAG_OBJECT); |
| 6357 | 6409 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 6379 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 6431 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 6380 __ movq(Operand(rax, Context::SlotOffset(i)), rbx); | 6432 __ movq(Operand(rax, Context::SlotOffset(i)), rbx); |
| 6381 } | 6433 } |
| 6382 | 6434 |
| 6383 // Return and remove the on-stack parameter. | 6435 // Return and remove the on-stack parameter. |
| 6384 __ movq(rsi, rax); | 6436 __ movq(rsi, rax); |
| 6385 __ ret(1 * kPointerSize); | 6437 __ ret(1 * kPointerSize); |
| 6386 | 6438 |
| 6387 // Need to collect. Call into runtime system. | 6439 // Need to collect. Call into runtime system. |
| 6388 __ bind(&gc); | 6440 __ bind(&gc); |
| 6389 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); | 6441 __ TailCallRuntime(Runtime::kNewContext, 1, 1); |
| 6390 } | 6442 } |
| 6391 | 6443 |
| 6392 | 6444 |
| 6393 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 6445 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 6394 // Stack layout on entry: | 6446 // Stack layout on entry: |
| 6395 // | 6447 // |
| 6396 // [rsp + kPointerSize]: constant elements. | 6448 // [rsp + kPointerSize]: constant elements. |
| 6397 // [rsp + (2 * kPointerSize)]: literal index. | 6449 // [rsp + (2 * kPointerSize)]: literal index. |
| 6398 // [rsp + (3 * kPointerSize)]: literals array. | 6450 // [rsp + (3 * kPointerSize)]: literals array. |
| 6399 | 6451 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6435 for (int i = 0; i < elements_size; i += kPointerSize) { | 6487 for (int i = 0; i < elements_size; i += kPointerSize) { |
| 6436 __ movq(rbx, FieldOperand(rcx, i)); | 6488 __ movq(rbx, FieldOperand(rcx, i)); |
| 6437 __ movq(FieldOperand(rdx, i), rbx); | 6489 __ movq(FieldOperand(rdx, i), rbx); |
| 6438 } | 6490 } |
| 6439 } | 6491 } |
| 6440 | 6492 |
| 6441 // Return and remove the on-stack parameters. | 6493 // Return and remove the on-stack parameters. |
| 6442 __ ret(3 * kPointerSize); | 6494 __ ret(3 * kPointerSize); |
| 6443 | 6495 |
| 6444 __ bind(&slow_case); | 6496 __ bind(&slow_case); |
| 6445 ExternalReference runtime(Runtime::kCreateArrayLiteralShallow); | 6497 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 6446 __ TailCallRuntime(runtime, 3, 1); | |
| 6447 } | 6498 } |
| 6448 | 6499 |
| 6449 | 6500 |
| 6450 void ToBooleanStub::Generate(MacroAssembler* masm) { | 6501 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 6451 Label false_result, true_result, not_string; | 6502 Label false_result, true_result, not_string; |
| 6452 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 6503 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 6453 | 6504 |
| 6454 // 'null' => false. | 6505 // 'null' => false. |
| 6455 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 6506 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 6456 __ j(equal, &false_result); | 6507 __ j(equal, &false_result); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6795 UNREACHABLE(); | 6846 UNREACHABLE(); |
| 6796 } | 6847 } |
| 6797 } | 6848 } |
| 6798 | 6849 |
| 6799 | 6850 |
| 6800 void RegExpExecStub::Generate(MacroAssembler* masm) { | 6851 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 6801 // Just jump directly to runtime if native RegExp is not selected at compile | 6852 // Just jump directly to runtime if native RegExp is not selected at compile |
| 6802 // time or if regexp entry in generated code is turned off runtime switch or | 6853 // time or if regexp entry in generated code is turned off runtime switch or |
| 6803 // at compilation. | 6854 // at compilation. |
| 6804 #ifndef V8_NATIVE_REGEXP | 6855 #ifndef V8_NATIVE_REGEXP |
| 6805 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); | 6856 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 6806 #else // V8_NATIVE_REGEXP | 6857 #else // V8_NATIVE_REGEXP |
| 6807 if (!FLAG_regexp_entry_native) { | 6858 if (!FLAG_regexp_entry_native) { |
| 6808 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); | 6859 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 6809 return; | 6860 return; |
| 6810 } | 6861 } |
| 6811 | 6862 |
| 6812 // Stack frame on entry. | 6863 // Stack frame on entry. |
| 6813 // esp[0]: return address | 6864 // esp[0]: return address |
| 6814 // esp[8]: last_match_info (expected JSArray) | 6865 // esp[8]: last_match_info (expected JSArray) |
| 6815 // esp[16]: previous index | 6866 // esp[16]: previous index |
| 6816 // esp[24]: subject string | 6867 // esp[24]: subject string |
| 6817 // esp[32]: JSRegExp object | 6868 // esp[32]: JSRegExp object |
| 6818 | 6869 |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7142 rdi); | 7193 rdi); |
| 7143 __ jmp(&next_capture); | 7194 __ jmp(&next_capture); |
| 7144 __ bind(&done); | 7195 __ bind(&done); |
| 7145 | 7196 |
| 7146 // Return last match info. | 7197 // Return last match info. |
| 7147 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); | 7198 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); |
| 7148 __ ret(4 * kPointerSize); | 7199 __ ret(4 * kPointerSize); |
| 7149 | 7200 |
| 7150 // Do the runtime call to execute the regexp. | 7201 // Do the runtime call to execute the regexp. |
| 7151 __ bind(&runtime); | 7202 __ bind(&runtime); |
| 7152 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); | 7203 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 7153 #endif // V8_NATIVE_REGEXP | 7204 #endif // V8_NATIVE_REGEXP |
| 7154 } | 7205 } |
| 7155 | 7206 |
| 7156 | 7207 |
| 7157 void CompareStub::Generate(MacroAssembler* masm) { | 7208 void CompareStub::Generate(MacroAssembler* masm) { |
| 7158 Label call_builtin, done; | 7209 Label call_builtin, done; |
| 7159 | 7210 |
| 7160 // NOTICE! This code is only reached after a smi-fast-case check, so | 7211 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 7161 // it is certain that at least one operand isn't a smi. | 7212 // it is certain that at least one operand isn't a smi. |
| 7162 | 7213 |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7553 __ subq(rdx, Immediate(kPointerSize)); | 7604 __ subq(rdx, Immediate(kPointerSize)); |
| 7554 __ decq(rcx); | 7605 __ decq(rcx); |
| 7555 __ j(not_zero, &loop); | 7606 __ j(not_zero, &loop); |
| 7556 | 7607 |
| 7557 // Return and remove the on-stack parameters. | 7608 // Return and remove the on-stack parameters. |
| 7558 __ bind(&done); | 7609 __ bind(&done); |
| 7559 __ ret(3 * kPointerSize); | 7610 __ ret(3 * kPointerSize); |
| 7560 | 7611 |
| 7561 // Do the runtime call to allocate the arguments object. | 7612 // Do the runtime call to allocate the arguments object. |
| 7562 __ bind(&runtime); | 7613 __ bind(&runtime); |
| 7563 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); | 7614 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 7564 } | 7615 } |
| 7565 | 7616 |
| 7566 | 7617 |
| 7567 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { | 7618 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| 7568 // The key is in rdx and the parameter count is in rax. | 7619 // The key is in rdx and the parameter count is in rax. |
| 7569 | 7620 |
| 7570 // The displacement is used for skipping the frame pointer on the | 7621 // The displacement is used for skipping the frame pointer on the |
| 7571 // stack. It is the offset of the last parameter (if any) relative | 7622 // stack. It is the offset of the last parameter (if any) relative |
| 7572 // to the frame pointer. | 7623 // to the frame pointer. |
| 7573 static const int kDisplacement = 1 * kPointerSize; | 7624 static const int kDisplacement = 1 * kPointerSize; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7610 index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); | 7661 index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); |
| 7611 __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); | 7662 __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); |
| 7612 __ Ret(); | 7663 __ Ret(); |
| 7613 | 7664 |
| 7614 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 7665 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 7615 // by calling the runtime system. | 7666 // by calling the runtime system. |
| 7616 __ bind(&slow); | 7667 __ bind(&slow); |
| 7617 __ pop(rbx); // Return address. | 7668 __ pop(rbx); // Return address. |
| 7618 __ push(rdx); | 7669 __ push(rdx); |
| 7619 __ push(rbx); | 7670 __ push(rbx); |
| 7620 Runtime::Function* f = | 7671 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 7621 Runtime::FunctionForId(Runtime::kGetArgumentsProperty); | |
| 7622 __ TailCallRuntime(ExternalReference(f), 1, f->result_size); | |
| 7623 } | 7672 } |
| 7624 | 7673 |
| 7625 | 7674 |
| 7626 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { | 7675 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { |
| 7627 // Check if the calling frame is an arguments adaptor frame. | 7676 // Check if the calling frame is an arguments adaptor frame. |
| 7628 Label adaptor; | 7677 Label adaptor; |
| 7629 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 7678 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 7630 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), | 7679 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), |
| 7631 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 7680 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 7632 | 7681 |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8101 void StackCheckStub::Generate(MacroAssembler* masm) { | 8150 void StackCheckStub::Generate(MacroAssembler* masm) { |
| 8102 // Because builtins always remove the receiver from the stack, we | 8151 // Because builtins always remove the receiver from the stack, we |
| 8103 // have to fake one to avoid underflowing the stack. The receiver | 8152 // have to fake one to avoid underflowing the stack. The receiver |
| 8104 // must be inserted below the return address on the stack so we | 8153 // must be inserted below the return address on the stack so we |
| 8105 // temporarily store that in a register. | 8154 // temporarily store that in a register. |
| 8106 __ pop(rax); | 8155 __ pop(rax); |
| 8107 __ Push(Smi::FromInt(0)); | 8156 __ Push(Smi::FromInt(0)); |
| 8108 __ push(rax); | 8157 __ push(rax); |
| 8109 | 8158 |
| 8110 // Do tail-call to runtime routine. | 8159 // Do tail-call to runtime routine. |
| 8111 Runtime::Function* f = Runtime::FunctionForId(Runtime::kStackGuard); | 8160 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); |
| 8112 __ TailCallRuntime(ExternalReference(f), 1, f->result_size); | |
| 8113 } | 8161 } |
| 8114 | 8162 |
| 8115 | 8163 |
| 8116 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 8164 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| 8117 Register number) { | 8165 Register number) { |
| 8118 Label load_smi, done; | 8166 Label load_smi, done; |
| 8119 | 8167 |
| 8120 __ JumpIfSmi(number, &load_smi); | 8168 __ JumpIfSmi(number, &load_smi); |
| 8121 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); | 8169 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); |
| 8122 __ jmp(&done); | 8170 __ jmp(&done); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8286 } | 8334 } |
| 8287 | 8335 |
| 8288 OS::SNPrintF(Vector<char>(name_, len), | 8336 OS::SNPrintF(Vector<char>(name_, len), |
| 8289 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", | 8337 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", |
| 8290 op_name, | 8338 op_name, |
| 8291 overwrite_name, | 8339 overwrite_name, |
| 8292 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 8340 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
| 8293 args_in_registers_ ? "RegArgs" : "StackArgs", | 8341 args_in_registers_ ? "RegArgs" : "StackArgs", |
| 8294 args_reversed_ ? "_R" : "", | 8342 args_reversed_ ? "_R" : "", |
| 8295 use_sse3_ ? "SSE3" : "SSE2", | 8343 use_sse3_ ? "SSE3" : "SSE2", |
| 8296 NumberInfo::ToString(operands_type_)); | 8344 operands_type_.ToString()); |
| 8297 return name_; | 8345 return name_; |
| 8298 } | 8346 } |
| 8299 | 8347 |
| 8300 | 8348 |
| 8301 void GenericBinaryOpStub::GenerateCall( | 8349 void GenericBinaryOpStub::GenerateCall( |
| 8302 MacroAssembler* masm, | 8350 MacroAssembler* masm, |
| 8303 Register left, | 8351 Register left, |
| 8304 Register right) { | 8352 Register right) { |
| 8305 if (!ArgsInRegistersSupported()) { | 8353 if (!ArgsInRegistersSupported()) { |
| 8306 // Pass arguments on the stack. | 8354 // Pass arguments on the stack. |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8610 GenerateLoadArguments(masm); | 8658 GenerateLoadArguments(masm); |
| 8611 } | 8659 } |
| 8612 // Floating point case. | 8660 // Floating point case. |
| 8613 switch (op_) { | 8661 switch (op_) { |
| 8614 case Token::ADD: | 8662 case Token::ADD: |
| 8615 case Token::SUB: | 8663 case Token::SUB: |
| 8616 case Token::MUL: | 8664 case Token::MUL: |
| 8617 case Token::DIV: { | 8665 case Token::DIV: { |
| 8618 // rax: y | 8666 // rax: y |
| 8619 // rdx: x | 8667 // rdx: x |
| 8620 if (NumberInfo::IsNumber(operands_type_)) { | 8668 if (operands_type_.IsNumber()) { |
| 8621 if (FLAG_debug_code) { | 8669 if (FLAG_debug_code) { |
| 8622 // Assert at runtime that inputs are only numbers. | 8670 // Assert at runtime that inputs are only numbers. |
| 8623 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); | 8671 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); |
| 8624 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); | 8672 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); |
| 8625 } | 8673 } |
| 8626 } else { | 8674 } else { |
| 8627 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); | 8675 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); |
| 8628 } | 8676 } |
| 8629 // Fast-case: Both operands are numbers. | 8677 // Fast-case: Both operands are numbers. |
| 8630 // xmm4 and xmm5 are volatile XMM registers. | 8678 // xmm4 and xmm5 are volatile XMM registers. |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8852 // If arguments are not passed in registers remove them from the stack before | 8900 // If arguments are not passed in registers remove them from the stack before |
| 8853 // returning. | 8901 // returning. |
| 8854 if (!HasArgsInRegisters()) { | 8902 if (!HasArgsInRegisters()) { |
| 8855 __ ret(2 * kPointerSize); // Remove both operands | 8903 __ ret(2 * kPointerSize); // Remove both operands |
| 8856 } else { | 8904 } else { |
| 8857 __ ret(0); | 8905 __ ret(0); |
| 8858 } | 8906 } |
| 8859 } | 8907 } |
| 8860 | 8908 |
| 8861 | 8909 |
| 8910 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
| 8911 return Handle<Code>::null(); |
| 8912 } |
| 8913 |
| 8914 |
| 8862 int CompareStub::MinorKey() { | 8915 int CompareStub::MinorKey() { |
| 8863 // Encode the three parameters in a unique 16 bit value. | 8916 // Encode the three parameters in a unique 16 bit value. |
| 8864 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); | 8917 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); |
| 8865 int nnn_value = (never_nan_nan_ ? 2 : 0); | 8918 int nnn_value = (never_nan_nan_ ? 2 : 0); |
| 8866 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. | 8919 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. |
| 8867 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); | 8920 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); |
| 8868 } | 8921 } |
| 8869 | 8922 |
| 8870 | 8923 |
| 8871 const char* CompareStub::GetName() { | 8924 const char* CompareStub::GetName() { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8949 // First string is empty, result is second string which is in rdx. | 9002 // First string is empty, result is second string which is in rdx. |
| 8950 __ movq(rax, rdx); | 9003 __ movq(rax, rdx); |
| 8951 __ IncrementCounter(&Counters::string_add_native, 1); | 9004 __ IncrementCounter(&Counters::string_add_native, 1); |
| 8952 __ ret(2 * kPointerSize); | 9005 __ ret(2 * kPointerSize); |
| 8953 | 9006 |
| 8954 // Both strings are non-empty. | 9007 // Both strings are non-empty. |
| 8955 // rax: first string | 9008 // rax: first string |
| 8956 // rbx: length of first string | 9009 // rbx: length of first string |
| 8957 // rcx: length of second string | 9010 // rcx: length of second string |
| 8958 // rdx: second string | 9011 // rdx: second string |
| 8959 // r8: instance type of first string if string check was performed above | 9012 // r8: map of first string if string check was performed above |
| 8960 // r9: instance type of first string if string check was performed above | 9013 // r9: map of second string if string check was performed above |
| 8961 Label string_add_flat_result; | 9014 Label string_add_flat_result, longer_than_two; |
| 8962 __ bind(&both_not_zero_length); | 9015 __ bind(&both_not_zero_length); |
| 8963 // Look at the length of the result of adding the two strings. | 9016 |
| 8964 __ addl(rbx, rcx); | |
| 8965 // Use the runtime system when adding two one character strings, as it | |
| 8966 // contains optimizations for this specific case using the symbol table. | |
| 8967 __ cmpl(rbx, Immediate(2)); | |
| 8968 __ j(equal, &string_add_runtime); | |
| 8969 // If arguments where known to be strings, maps are not loaded to r8 and r9 | 9017 // If arguments where known to be strings, maps are not loaded to r8 and r9 |
| 8970 // by the code above. | 9018 // by the code above. |
| 8971 if (!string_check_) { | 9019 if (!string_check_) { |
| 8972 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | 9020 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
| 8973 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 9021 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 8974 } | 9022 } |
| 8975 // Get the instance types of the two strings as they will be needed soon. | 9023 // Get the instance types of the two strings as they will be needed soon. |
| 8976 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | 9024 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
| 8977 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | 9025 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
| 9026 |
| 9027 // Look at the length of the result of adding the two strings. |
| 9028 __ addl(rbx, rcx); |
| 9029 // Use the runtime system when adding two one character strings, as it |
| 9030 // contains optimizations for this specific case using the symbol table. |
| 9031 __ cmpl(rbx, Immediate(2)); |
| 9032 __ j(not_equal, &longer_than_two); |
| 9033 |
| 9034 // Check that both strings are non-external ascii strings. |
| 9035 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, |
| 9036 &string_add_runtime); |
| 9037 |
| 9038 // Get the two characters forming the sub string. |
| 9039 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
| 9040 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); |
| 9041 |
| 9042 // Try to lookup two character string in symbol table. If it is not found |
| 9043 // just allocate a new one. |
| 9044 Label make_two_character_string, make_flat_ascii_string; |
| 9045 GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, r14, r12, rdi, r15, |
| 9046 &make_two_character_string); |
| 9047 __ IncrementCounter(&Counters::string_add_native, 1); |
| 9048 __ ret(2 * kPointerSize); |
| 9049 |
| 9050 __ bind(&make_two_character_string); |
| 9051 __ Set(rbx, 2); |
| 9052 __ jmp(&make_flat_ascii_string); |
| 9053 |
| 9054 __ bind(&longer_than_two); |
| 8978 // Check if resulting string will be flat. | 9055 // Check if resulting string will be flat. |
| 8979 __ cmpl(rbx, Immediate(String::kMinNonFlatLength)); | 9056 __ cmpl(rbx, Immediate(String::kMinNonFlatLength)); |
| 8980 __ j(below, &string_add_flat_result); | 9057 __ j(below, &string_add_flat_result); |
| 8981 // Handle exceptionally long strings in the runtime system. | 9058 // Handle exceptionally long strings in the runtime system. |
| 8982 ASSERT((String::kMaxLength & 0x80000000) == 0); | 9059 ASSERT((String::kMaxLength & 0x80000000) == 0); |
| 8983 __ cmpl(rbx, Immediate(String::kMaxLength)); | 9060 __ cmpl(rbx, Immediate(String::kMaxLength)); |
| 8984 __ j(above, &string_add_runtime); | 9061 __ j(above, &string_add_runtime); |
| 8985 | 9062 |
| 8986 // If result is not supposed to be flat, allocate a cons string object. If | 9063 // If result is not supposed to be flat, allocate a cons string object. If |
| 8987 // both strings are ascii the result is an ascii cons string. | 9064 // both strings are ascii the result is an ascii cons string. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9034 // ebx: length of resulting flat string | 9111 // ebx: length of resulting flat string |
| 9035 // rdx: second string | 9112 // rdx: second string |
| 9036 // r8: instance type of first string | 9113 // r8: instance type of first string |
| 9037 // r9: instance type of second string | 9114 // r9: instance type of second string |
| 9038 Label non_ascii_string_add_flat_result; | 9115 Label non_ascii_string_add_flat_result; |
| 9039 ASSERT(kStringEncodingMask == kAsciiStringTag); | 9116 ASSERT(kStringEncodingMask == kAsciiStringTag); |
| 9040 __ testl(r8, Immediate(kAsciiStringTag)); | 9117 __ testl(r8, Immediate(kAsciiStringTag)); |
| 9041 __ j(zero, &non_ascii_string_add_flat_result); | 9118 __ j(zero, &non_ascii_string_add_flat_result); |
| 9042 __ testl(r9, Immediate(kAsciiStringTag)); | 9119 __ testl(r9, Immediate(kAsciiStringTag)); |
| 9043 __ j(zero, &string_add_runtime); | 9120 __ j(zero, &string_add_runtime); |
| 9121 |
| 9122 __ bind(&make_flat_ascii_string); |
| 9044 // Both strings are ascii strings. As they are short they are both flat. | 9123 // Both strings are ascii strings. As they are short they are both flat. |
| 9045 __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); | 9124 __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); |
| 9046 // rcx: result string | 9125 // rcx: result string |
| 9047 __ movq(rbx, rcx); | 9126 __ movq(rbx, rcx); |
| 9048 // Locate first character of result. | 9127 // Locate first character of result. |
| 9049 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9128 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9050 // Locate first character of first argument | 9129 // Locate first character of first argument |
| 9051 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); | 9130 __ movl(rdi, FieldOperand(rax, String::kLengthOffset)); |
| 9052 __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9131 __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9053 // rax: first char of first argument | 9132 // rax: first char of first argument |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9100 // rcx: next character of result | 9179 // rcx: next character of result |
| 9101 // rdx: first char of second argument | 9180 // rdx: first char of second argument |
| 9102 // rdi: length of second argument | 9181 // rdi: length of second argument |
| 9103 GenerateCopyCharacters(masm, rcx, rdx, rdi, false); | 9182 GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
| 9104 __ movq(rax, rbx); | 9183 __ movq(rax, rbx); |
| 9105 __ IncrementCounter(&Counters::string_add_native, 1); | 9184 __ IncrementCounter(&Counters::string_add_native, 1); |
| 9106 __ ret(2 * kPointerSize); | 9185 __ ret(2 * kPointerSize); |
| 9107 | 9186 |
| 9108 // Just jump to runtime to add the two strings. | 9187 // Just jump to runtime to add the two strings. |
| 9109 __ bind(&string_add_runtime); | 9188 __ bind(&string_add_runtime); |
| 9110 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); | 9189 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 9111 } | 9190 } |
| 9112 | 9191 |
| 9113 | 9192 |
| 9114 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, | 9193 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, |
| 9115 Register dest, | 9194 Register dest, |
| 9116 Register src, | 9195 Register src, |
| 9117 Register count, | 9196 Register count, |
| 9118 bool ascii) { | 9197 bool ascii) { |
| 9119 Label loop; | 9198 Label loop; |
| 9120 __ bind(&loop); | 9199 __ bind(&loop); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9184 __ movb(kScratchRegister, Operand(src, 0)); | 9263 __ movb(kScratchRegister, Operand(src, 0)); |
| 9185 __ movb(Operand(dest, 0), kScratchRegister); | 9264 __ movb(Operand(dest, 0), kScratchRegister); |
| 9186 __ addq(src, Immediate(1)); | 9265 __ addq(src, Immediate(1)); |
| 9187 __ addq(dest, Immediate(1)); | 9266 __ addq(dest, Immediate(1)); |
| 9188 __ subq(count, Immediate(1)); | 9267 __ subq(count, Immediate(1)); |
| 9189 __ j(not_zero, &loop); | 9268 __ j(not_zero, &loop); |
| 9190 | 9269 |
| 9191 __ bind(&done); | 9270 __ bind(&done); |
| 9192 } | 9271 } |
| 9193 | 9272 |
| 9273 void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
| 9274 Register c1, |
| 9275 Register c2, |
| 9276 Register scratch1, |
| 9277 Register scratch2, |
| 9278 Register scratch3, |
| 9279 Register scratch4, |
| 9280 Label* not_found) { |
| 9281 // Register scratch3 is the general scratch register in this function. |
| 9282 Register scratch = scratch3; |
| 9283 |
| 9284 // Make sure that both characters are not digits as such strings has a |
| 9285 // different hash algorithm. Don't try to look for these in the symbol table. |
| 9286 Label not_array_index; |
| 9287 __ movq(scratch, c1); |
| 9288 __ subq(scratch, Immediate(static_cast<int>('0'))); |
| 9289 __ cmpq(scratch, Immediate(static_cast<int>('9' - '0'))); |
| 9290 __ j(above, ¬_array_index); |
| 9291 __ movq(scratch, c2); |
| 9292 __ subq(scratch, Immediate(static_cast<int>('0'))); |
| 9293 __ cmpq(scratch, Immediate(static_cast<int>('9' - '0'))); |
| 9294 __ j(below_equal, not_found); |
| 9295 |
| 9296 __ bind(¬_array_index); |
| 9297 // Calculate the two character string hash. |
| 9298 Register hash = scratch1; |
| 9299 GenerateHashInit(masm, hash, c1, scratch); |
| 9300 GenerateHashAddCharacter(masm, hash, c2, scratch); |
| 9301 GenerateHashGetHash(masm, hash, scratch); |
| 9302 |
| 9303 // Collect the two characters in a register. |
| 9304 Register chars = c1; |
| 9305 __ shl(c2, Immediate(kBitsPerByte)); |
| 9306 __ orl(chars, c2); |
| 9307 |
| 9308 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 9309 // hash: hash of two character string. |
| 9310 |
| 9311 // Load the symbol table. |
| 9312 Register symbol_table = c2; |
| 9313 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); |
| 9314 |
| 9315 // Calculate capacity mask from the symbol table capacity. |
| 9316 Register mask = scratch2; |
| 9317 __ movq(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); |
| 9318 __ SmiToInteger32(mask, mask); |
| 9319 __ decl(mask); |
| 9320 |
| 9321 Register undefined = scratch4; |
| 9322 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); |
| 9323 |
| 9324 // Registers |
| 9325 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 9326 // hash: hash of two character string (32-bit int) |
| 9327 // symbol_table: symbol table |
| 9328 // mask: capacity mask (32-bit int) |
| 9329 // undefined: undefined value |
| 9330 // scratch: - |
| 9331 |
| 9332 // Perform a number of probes in the symbol table. |
| 9333 static const int kProbes = 4; |
| 9334 Label found_in_symbol_table; |
| 9335 Label next_probe[kProbes]; |
| 9336 for (int i = 0; i < kProbes; i++) { |
| 9337 // Calculate entry in symbol table. |
| 9338 __ movl(scratch, hash); |
| 9339 if (i > 0) { |
| 9340 __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i))); |
| 9341 } |
| 9342 __ andl(scratch, mask); |
| 9343 |
| 9344 // Load the entry from the symble table. |
| 9345 Register candidate = scratch; // Scratch register contains candidate. |
| 9346 ASSERT_EQ(1, SymbolTable::kEntrySize); |
| 9347 __ movq(candidate, |
| 9348 FieldOperand(symbol_table, |
| 9349 scratch, |
| 9350 times_pointer_size, |
| 9351 SymbolTable::kElementsStartOffset)); |
| 9352 |
| 9353 // If entry is undefined no string with this hash can be found. |
| 9354 __ cmpq(candidate, undefined); |
| 9355 __ j(equal, not_found); |
| 9356 |
| 9357 // If length is not 2 the string is not a candidate. |
| 9358 __ cmpl(FieldOperand(candidate, String::kLengthOffset), Immediate(2)); |
| 9359 __ j(not_equal, &next_probe[i]); |
| 9360 |
| 9361 // We use kScratchRegister as a temporary register in assumption that |
| 9362 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly |
| 9363 Register temp = kScratchRegister; |
| 9364 |
| 9365 // Check that the candidate is a non-external ascii string. |
| 9366 __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset)); |
| 9367 __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); |
| 9368 __ JumpIfInstanceTypeIsNotSequentialAscii( |
| 9369 temp, temp, &next_probe[i]); |
| 9370 |
| 9371 // Check if the two characters match. |
| 9372 __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); |
| 9373 __ andl(temp, Immediate(0x0000ffff)); |
| 9374 __ cmpl(chars, temp); |
| 9375 __ j(equal, &found_in_symbol_table); |
| 9376 __ bind(&next_probe[i]); |
| 9377 } |
| 9378 |
| 9379 // No matching 2 character string found by probing. |
| 9380 __ jmp(not_found); |
| 9381 |
| 9382 // Scratch register contains result when we fall through to here. |
| 9383 Register result = scratch; |
| 9384 __ bind(&found_in_symbol_table); |
| 9385 if (!result.is(rax)) { |
| 9386 __ movq(rax, result); |
| 9387 } |
| 9388 } |
| 9389 |
| 9390 |
| 9391 void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
| 9392 Register hash, |
| 9393 Register character, |
| 9394 Register scratch) { |
| 9395 // hash = character + (character << 10); |
| 9396 __ movl(hash, character); |
| 9397 __ shll(hash, Immediate(10)); |
| 9398 __ addl(hash, character); |
| 9399 // hash ^= hash >> 6; |
| 9400 __ movl(scratch, hash); |
| 9401 __ sarl(scratch, Immediate(6)); |
| 9402 __ xorl(hash, scratch); |
| 9403 } |
| 9404 |
| 9405 |
| 9406 void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
| 9407 Register hash, |
| 9408 Register character, |
| 9409 Register scratch) { |
| 9410 // hash += character; |
| 9411 __ addl(hash, character); |
| 9412 // hash += hash << 10; |
| 9413 __ movl(scratch, hash); |
| 9414 __ shll(scratch, Immediate(10)); |
| 9415 __ addl(hash, scratch); |
| 9416 // hash ^= hash >> 6; |
| 9417 __ movl(scratch, hash); |
| 9418 __ sarl(scratch, Immediate(6)); |
| 9419 __ xorl(hash, scratch); |
| 9420 } |
| 9421 |
| 9422 |
| 9423 void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
| 9424 Register hash, |
| 9425 Register scratch) { |
| 9426 // hash += hash << 3; |
| 9427 __ movl(scratch, hash); |
| 9428 __ shll(scratch, Immediate(3)); |
| 9429 __ addl(hash, scratch); |
| 9430 // hash ^= hash >> 11; |
| 9431 __ movl(scratch, hash); |
| 9432 __ sarl(scratch, Immediate(11)); |
| 9433 __ xorl(hash, scratch); |
| 9434 // hash += hash << 15; |
| 9435 __ movl(scratch, hash); |
| 9436 __ shll(scratch, Immediate(15)); |
| 9437 __ addl(hash, scratch); |
| 9438 |
| 9439 // if (hash == 0) hash = 27; |
| 9440 Label hash_not_zero; |
| 9441 __ testl(hash, hash); |
| 9442 __ j(not_zero, &hash_not_zero); |
| 9443 __ movl(hash, Immediate(27)); |
| 9444 __ bind(&hash_not_zero); |
| 9445 } |
| 9194 | 9446 |
| 9195 void SubStringStub::Generate(MacroAssembler* masm) { | 9447 void SubStringStub::Generate(MacroAssembler* masm) { |
| 9196 Label runtime; | 9448 Label runtime; |
| 9197 | 9449 |
| 9198 // Stack frame on entry. | 9450 // Stack frame on entry. |
| 9199 // rsp[0]: return address | 9451 // rsp[0]: return address |
| 9200 // rsp[8]: to | 9452 // rsp[8]: to |
| 9201 // rsp[16]: from | 9453 // rsp[16]: from |
| 9202 // rsp[24]: string | 9454 // rsp[24]: string |
| 9203 | 9455 |
| 9204 const int kToOffset = 1 * kPointerSize; | 9456 const int kToOffset = 1 * kPointerSize; |
| 9205 const int kFromOffset = kToOffset + kPointerSize; | 9457 const int kFromOffset = kToOffset + kPointerSize; |
| 9206 const int kStringOffset = kFromOffset + kPointerSize; | 9458 const int kStringOffset = kFromOffset + kPointerSize; |
| 9207 const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset; | 9459 const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset; |
| 9208 | 9460 |
| 9209 // Make sure first argument is a string. | 9461 // Make sure first argument is a string. |
| 9210 __ movq(rax, Operand(rsp, kStringOffset)); | 9462 __ movq(rax, Operand(rsp, kStringOffset)); |
| 9211 ASSERT_EQ(0, kSmiTag); | 9463 ASSERT_EQ(0, kSmiTag); |
| 9212 __ testl(rax, Immediate(kSmiTagMask)); | 9464 __ testl(rax, Immediate(kSmiTagMask)); |
| 9213 __ j(zero, &runtime); | 9465 __ j(zero, &runtime); |
| 9214 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); | 9466 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); |
| 9215 __ j(NegateCondition(is_string), &runtime); | 9467 __ j(NegateCondition(is_string), &runtime); |
| 9216 | 9468 |
| 9217 // rax: string | 9469 // rax: string |
| 9218 // rbx: instance type | 9470 // rbx: instance type |
| 9219 // Calculate length of sub string using the smi values. | 9471 // Calculate length of sub string using the smi values. |
| 9472 Label result_longer_than_two; |
| 9220 __ movq(rcx, Operand(rsp, kToOffset)); | 9473 __ movq(rcx, Operand(rsp, kToOffset)); |
| 9221 __ movq(rdx, Operand(rsp, kFromOffset)); | 9474 __ movq(rdx, Operand(rsp, kFromOffset)); |
| 9222 __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime); | 9475 __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime); |
| 9223 | 9476 |
| 9224 __ SmiSub(rcx, rcx, rdx, NULL); // Overflow doesn't happen. | 9477 __ SmiSub(rcx, rcx, rdx, NULL); // Overflow doesn't happen. |
| 9225 __ j(negative, &runtime); | 9478 __ j(negative, &runtime); |
| 9226 // Handle sub-strings of length 2 and less in the runtime system. | 9479 // Special handling of sub-strings of length 1 and 2. One character strings |
| 9480 // are handled in the runtime system (looked up in the single character |
| 9481 // cache). Two character strings are looked for in the symbol cache. |
| 9227 __ SmiToInteger32(rcx, rcx); | 9482 __ SmiToInteger32(rcx, rcx); |
| 9228 __ cmpl(rcx, Immediate(2)); | 9483 __ cmpl(rcx, Immediate(2)); |
| 9229 __ j(below_equal, &runtime); | 9484 __ j(greater, &result_longer_than_two); |
| 9485 __ j(less, &runtime); |
| 9486 |
| 9487 // Sub string of length 2 requested. |
| 9488 // rax: string |
| 9489 // rbx: instance type |
| 9490 // rcx: sub string length (value is 2) |
| 9491 // rdx: from index (smi) |
| 9492 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime); |
| 9493 |
| 9494 // Get the two characters forming the sub string. |
| 9495 __ SmiToInteger32(rdx, rdx); // From index is no longer smi. |
| 9496 __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); |
| 9497 __ movzxbq(rcx, |
| 9498 FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1)); |
| 9499 |
| 9500 // Try to lookup two character string in symbol table. |
| 9501 Label make_two_character_string; |
| 9502 GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, rax, rdx, rdi, r14, |
| 9503 &make_two_character_string); |
| 9504 __ ret(3 * kPointerSize); |
| 9505 |
| 9506 __ bind(&make_two_character_string); |
| 9507 // Setup registers for allocating the two character string. |
| 9508 __ movq(rax, Operand(rsp, kStringOffset)); |
| 9509 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 9510 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 9511 __ Set(rcx, 2); |
| 9512 |
| 9513 __ bind(&result_longer_than_two); |
| 9230 | 9514 |
| 9231 // rax: string | 9515 // rax: string |
| 9232 // rbx: instance type | 9516 // rbx: instance type |
| 9233 // rcx: result string length | 9517 // rcx: result string length |
| 9234 // Check for flat ascii string | 9518 // Check for flat ascii string |
| 9235 Label non_ascii_flat; | 9519 Label non_ascii_flat; |
| 9236 __ and_(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask)); | 9520 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat); |
| 9237 __ cmpb(rbx, Immediate(kSeqStringTag | kAsciiStringTag)); | |
| 9238 __ j(not_equal, &non_ascii_flat); | |
| 9239 | 9521 |
| 9240 // Allocate the result. | 9522 // Allocate the result. |
| 9241 __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); | 9523 __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); |
| 9242 | 9524 |
| 9243 // rax: result string | 9525 // rax: result string |
| 9244 // rcx: result string length | 9526 // rcx: result string length |
| 9245 __ movq(rdx, rsi); // esi used by following code. | 9527 __ movq(rdx, rsi); // esi used by following code. |
| 9246 // Locate first character of result. | 9528 // Locate first character of result. |
| 9247 __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); | 9529 __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
| 9248 // Load string argument and locate character of sub string start. | 9530 // Load string argument and locate character of sub string start. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9294 // rdx: original value of rsi | 9576 // rdx: original value of rsi |
| 9295 // rdi: first character of result | 9577 // rdi: first character of result |
| 9296 // rsi: character of sub string start | 9578 // rsi: character of sub string start |
| 9297 GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); | 9579 GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); |
| 9298 __ movq(rsi, rdx); // Restore esi. | 9580 __ movq(rsi, rdx); // Restore esi. |
| 9299 __ IncrementCounter(&Counters::sub_string_native, 1); | 9581 __ IncrementCounter(&Counters::sub_string_native, 1); |
| 9300 __ ret(kArgumentsSize); | 9582 __ ret(kArgumentsSize); |
| 9301 | 9583 |
| 9302 // Just jump to runtime to create the sub string. | 9584 // Just jump to runtime to create the sub string. |
| 9303 __ bind(&runtime); | 9585 __ bind(&runtime); |
| 9304 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); | 9586 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 9305 } | 9587 } |
| 9306 | 9588 |
| 9307 | 9589 |
| 9308 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 9590 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 9309 Register left, | 9591 Register left, |
| 9310 Register right, | 9592 Register right, |
| 9311 Register scratch1, | 9593 Register scratch1, |
| 9312 Register scratch2, | 9594 Register scratch2, |
| 9313 Register scratch3, | 9595 Register scratch3, |
| 9314 Register scratch4) { | 9596 Register scratch4) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9414 // Check that both are sequential ASCII strings. | 9696 // Check that both are sequential ASCII strings. |
| 9415 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); | 9697 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); |
| 9416 | 9698 |
| 9417 // Inline comparison of ascii strings. | 9699 // Inline comparison of ascii strings. |
| 9418 __ IncrementCounter(&Counters::string_compare_native, 1); | 9700 __ IncrementCounter(&Counters::string_compare_native, 1); |
| 9419 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); | 9701 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); |
| 9420 | 9702 |
| 9421 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 9703 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 9422 // tagged as a small integer. | 9704 // tagged as a small integer. |
| 9423 __ bind(&runtime); | 9705 __ bind(&runtime); |
| 9424 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 9706 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 9425 } | 9707 } |
| 9426 | 9708 |
| 9427 #undef __ | 9709 #undef __ |
| 9428 | 9710 |
| 9429 #define __ masm. | 9711 #define __ masm. |
| 9430 | 9712 |
| 9431 #ifdef _WIN64 | 9713 #ifdef _WIN64 |
| 9432 typedef double (*ModuloFunction)(double, double); | 9714 typedef double (*ModuloFunction)(double, double); |
| 9433 // Define custom fmod implementation. | 9715 // Define custom fmod implementation. |
| 9434 ModuloFunction CreateModuloFunction() { | 9716 ModuloFunction CreateModuloFunction() { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9514 // Call the function from C++. | 9796 // Call the function from C++. |
| 9515 return FUNCTION_CAST<ModuloFunction>(buffer); | 9797 return FUNCTION_CAST<ModuloFunction>(buffer); |
| 9516 } | 9798 } |
| 9517 | 9799 |
| 9518 #endif | 9800 #endif |
| 9519 | 9801 |
| 9520 | 9802 |
| 9521 #undef __ | 9803 #undef __ |
| 9522 | 9804 |
| 9523 } } // namespace v8::internal | 9805 } } // namespace v8::internal |
| OLD | NEW |