OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/ast/ast.h" | 9 #include "src/ast/ast.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 4148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4159 assembler->Bind(&if_notequal); | 4159 assembler->Bind(&if_notequal); |
4160 { | 4160 { |
4161 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); | 4161 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); |
4162 assembler->Goto(&end); | 4162 assembler->Goto(&end); |
4163 } | 4163 } |
4164 | 4164 |
4165 assembler->Bind(&end); | 4165 assembler->Bind(&end); |
4166 return result.value(); | 4166 return result.value(); |
4167 } | 4167 } |
4168 | 4168 |
4169 void GenerateStringRelationalComparison(CodeStubAssembler* assembler, | |
4170 RelationalComparisonMode mode) { | |
4171 typedef CodeStubAssembler::Label Label; | |
4172 typedef compiler::Node Node; | |
4173 typedef CodeStubAssembler::Variable Variable; | |
4174 | |
4175 Node* lhs = assembler->Parameter(0); | |
4176 Node* rhs = assembler->Parameter(1); | |
4177 Node* context = assembler->Parameter(2); | |
4178 | |
4179 Label if_less(assembler), if_equal(assembler), if_greater(assembler); | |
4180 | |
4181 // Fast check to see if {lhs} and {rhs} refer to the same String object. | |
4182 Label if_same(assembler), if_notsame(assembler); | |
4183 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
4184 | |
4185 assembler->Bind(&if_same); | |
4186 assembler->Goto(&if_equal); | |
4187 | |
4188 assembler->Bind(&if_notsame); | |
4189 { | |
4190 // Load instance types of {lhs} and {rhs}. | |
4191 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | |
4192 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
4193 | |
4194 // Combine the instance types into a single 16-bit value, so we can check | |
4195 // both of them at once. | |
4196 Node* both_instance_types = assembler->Word32Or( | |
4197 lhs_instance_type, | |
4198 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); | |
4199 | |
4200 // Check that both {lhs} and {rhs} are flat one-byte strings. | |
4201 int const kBothSeqOneByteStringMask = | |
4202 kStringEncodingMask | kStringRepresentationMask | | |
4203 ((kStringEncodingMask | kStringRepresentationMask) << 8); | |
4204 int const kBothSeqOneByteStringTag = | |
4205 kOneByteStringTag | kSeqStringTag | | |
4206 ((kOneByteStringTag | kSeqStringTag) << 8); | |
4207 Label if_bothonebyteseqstrings(assembler), | |
4208 if_notbothonebyteseqstrings(assembler); | |
4209 assembler->Branch(assembler->Word32Equal( | |
4210 assembler->Word32And(both_instance_types, | |
4211 assembler->Int32Constant( | |
4212 kBothSeqOneByteStringMask)), | |
4213 assembler->Int32Constant(kBothSeqOneByteStringTag)), | |
4214 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); | |
4215 | |
4216 assembler->Bind(&if_bothonebyteseqstrings); | |
4217 { | |
4218 // Load the length of {lhs} and {rhs}. | |
4219 Node* lhs_length = assembler->LoadStringLength(lhs); | |
4220 Node* rhs_length = assembler->LoadStringLength(rhs); | |
4221 | |
4222 // Determine the minimum length. | |
4223 Node* length = assembler->SmiMin(lhs_length, rhs_length); | |
4224 | |
4225 // Compute the effective offset of the first character. | |
4226 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
4227 kHeapObjectTag); | |
4228 | |
4229 // Compute the first offset after the string from the length. | |
4230 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length)); | |
4231 | |
4232 // Loop over the {lhs} and {rhs} strings to see if they are equal. | |
4233 Variable var_offset(assembler, MachineType::PointerRepresentation()); | |
4234 Label loop(assembler, &var_offset); | |
4235 var_offset.Bind(begin); | |
4236 assembler->Goto(&loop); | |
4237 assembler->Bind(&loop); | |
4238 { | |
4239 // Check if {offset} equals {end}. | |
4240 Node* offset = var_offset.value(); | |
4241 Label if_done(assembler), if_notdone(assembler); | |
4242 assembler->Branch(assembler->WordEqual(offset, end), &if_done, | |
4243 &if_notdone); | |
4244 | |
4245 assembler->Bind(&if_notdone); | |
4246 { | |
4247 // Load the next characters from {lhs} and {rhs}. | |
4248 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset); | |
4249 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset); | |
4250 | |
4251 // Check if the characters match. | |
4252 Label if_valueissame(assembler), if_valueisnotsame(assembler); | |
4253 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), | |
4254 &if_valueissame, &if_valueisnotsame); | |
4255 | |
4256 assembler->Bind(&if_valueissame); | |
4257 { | |
4258 // Advance to next character. | |
4259 var_offset.Bind( | |
4260 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | |
4261 } | |
4262 assembler->Goto(&loop); | |
4263 | |
4264 assembler->Bind(&if_valueisnotsame); | |
4265 assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value), | |
4266 &if_less, &if_greater); | |
4267 } | |
4268 | |
4269 assembler->Bind(&if_done); | |
4270 { | |
4271 // All characters up to the min length are equal, decide based on | |
4272 // string length. | |
4273 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); | |
4274 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length), | |
4275 &if_lengthisequal, &if_lengthisnotequal); | |
4276 | |
4277 assembler->Bind(&if_lengthisequal); | |
4278 assembler->Goto(&if_equal); | |
4279 | |
4280 assembler->Bind(&if_lengthisnotequal); | |
4281 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, | |
4282 &if_greater); | |
4283 } | |
4284 } | |
4285 } | |
4286 | |
4287 assembler->Bind(&if_notbothonebyteseqstrings); | |
4288 { | |
4289 // TODO(bmeurer): Add fast case support for flattened cons strings; | |
4290 // also add support for two byte string relational comparisons. | |
4291 switch (mode) { | |
4292 case kLessThan: | |
4293 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs, | |
4294 rhs); | |
4295 break; | |
4296 case kLessThanOrEqual: | |
4297 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context, | |
4298 lhs, rhs); | |
4299 break; | |
4300 case kGreaterThan: | |
4301 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, | |
4302 rhs); | |
4303 break; | |
4304 case kGreaterThanOrEqual: | |
4305 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual, | |
4306 context, lhs, rhs); | |
4307 break; | |
4308 } | |
4309 } | |
4310 } | |
4311 | |
4312 assembler->Bind(&if_less); | |
4313 switch (mode) { | |
4314 case kLessThan: | |
4315 case kLessThanOrEqual: | |
4316 assembler->Return(assembler->BooleanConstant(true)); | |
4317 break; | |
4318 | |
4319 case kGreaterThan: | |
4320 case kGreaterThanOrEqual: | |
4321 assembler->Return(assembler->BooleanConstant(false)); | |
4322 break; | |
4323 } | |
4324 | |
4325 assembler->Bind(&if_equal); | |
4326 switch (mode) { | |
4327 case kLessThan: | |
4328 case kGreaterThan: | |
4329 assembler->Return(assembler->BooleanConstant(false)); | |
4330 break; | |
4331 | |
4332 case kLessThanOrEqual: | |
4333 case kGreaterThanOrEqual: | |
4334 assembler->Return(assembler->BooleanConstant(true)); | |
4335 break; | |
4336 } | |
4337 | |
4338 assembler->Bind(&if_greater); | |
4339 switch (mode) { | |
4340 case kLessThan: | |
4341 case kLessThanOrEqual: | |
4342 assembler->Return(assembler->BooleanConstant(false)); | |
4343 break; | |
4344 | |
4345 case kGreaterThan: | |
4346 case kGreaterThanOrEqual: | |
4347 assembler->Return(assembler->BooleanConstant(true)); | |
4348 break; | |
4349 } | |
4350 } | |
4351 | |
4352 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) { | |
4353 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | |
4354 // mode; for kNegateResult mode we properly negate the result. | |
4355 // | |
4356 // if (lhs == rhs) return true; | |
4357 // if (lhs->length() != rhs->length()) return false; | |
4358 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { | |
4359 // return false; | |
4360 // } | |
4361 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { | |
4362 // for (i = 0; i != lhs->length(); ++i) { | |
4363 // if (lhs[i] != rhs[i]) return false; | |
4364 // } | |
4365 // return true; | |
4366 // } | |
4367 // return %StringEqual(lhs, rhs); | |
4368 | |
4369 typedef CodeStubAssembler::Label Label; | |
4370 typedef compiler::Node Node; | |
4371 typedef CodeStubAssembler::Variable Variable; | |
4372 | |
4373 Node* lhs = assembler->Parameter(0); | |
4374 Node* rhs = assembler->Parameter(1); | |
4375 Node* context = assembler->Parameter(2); | |
4376 | |
4377 Label if_equal(assembler), if_notequal(assembler); | |
4378 | |
4379 // Fast check to see if {lhs} and {rhs} refer to the same String object. | |
4380 Label if_same(assembler), if_notsame(assembler); | |
4381 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
4382 | |
4383 assembler->Bind(&if_same); | |
4384 assembler->Goto(&if_equal); | |
4385 | |
4386 assembler->Bind(&if_notsame); | |
4387 { | |
4388 // The {lhs} and {rhs} don't refer to the exact same String object. | |
4389 | |
4390 // Load the length of {lhs} and {rhs}. | |
4391 Node* lhs_length = assembler->LoadStringLength(lhs); | |
4392 Node* rhs_length = assembler->LoadStringLength(rhs); | |
4393 | |
4394 // Check if the lengths of {lhs} and {rhs} are equal. | |
4395 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); | |
4396 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), | |
4397 &if_lengthisequal, &if_lengthisnotequal); | |
4398 | |
4399 assembler->Bind(&if_lengthisequal); | |
4400 { | |
4401 // Load instance types of {lhs} and {rhs}. | |
4402 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | |
4403 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
4404 | |
4405 // Combine the instance types into a single 16-bit value, so we can check | |
4406 // both of them at once. | |
4407 Node* both_instance_types = assembler->Word32Or( | |
4408 lhs_instance_type, | |
4409 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); | |
4410 | |
4411 // Check if both {lhs} and {rhs} are internalized. | |
4412 int const kBothInternalizedMask = | |
4413 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); | |
4414 int const kBothInternalizedTag = | |
4415 kInternalizedTag | (kInternalizedTag << 8); | |
4416 Label if_bothinternalized(assembler), if_notbothinternalized(assembler); | |
4417 assembler->Branch(assembler->Word32Equal( | |
4418 assembler->Word32And(both_instance_types, | |
4419 assembler->Int32Constant( | |
4420 kBothInternalizedMask)), | |
4421 assembler->Int32Constant(kBothInternalizedTag)), | |
4422 &if_bothinternalized, &if_notbothinternalized); | |
4423 | |
4424 assembler->Bind(&if_bothinternalized); | |
4425 { | |
4426 // Fast negative check for internalized-to-internalized equality. | |
4427 assembler->Goto(&if_notequal); | |
4428 } | |
4429 | |
4430 assembler->Bind(&if_notbothinternalized); | |
4431 { | |
4432 // Check that both {lhs} and {rhs} are flat one-byte strings. | |
4433 int const kBothSeqOneByteStringMask = | |
4434 kStringEncodingMask | kStringRepresentationMask | | |
4435 ((kStringEncodingMask | kStringRepresentationMask) << 8); | |
4436 int const kBothSeqOneByteStringTag = | |
4437 kOneByteStringTag | kSeqStringTag | | |
4438 ((kOneByteStringTag | kSeqStringTag) << 8); | |
4439 Label if_bothonebyteseqstrings(assembler), | |
4440 if_notbothonebyteseqstrings(assembler); | |
4441 assembler->Branch( | |
4442 assembler->Word32Equal( | |
4443 assembler->Word32And( | |
4444 both_instance_types, | |
4445 assembler->Int32Constant(kBothSeqOneByteStringMask)), | |
4446 assembler->Int32Constant(kBothSeqOneByteStringTag)), | |
4447 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); | |
4448 | |
4449 assembler->Bind(&if_bothonebyteseqstrings); | |
4450 { | |
4451 // Compute the effective offset of the first character. | |
4452 Node* begin = assembler->IntPtrConstant( | |
4453 SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
4454 | |
4455 // Compute the first offset after the string from the length. | |
4456 Node* end = | |
4457 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length)); | |
4458 | |
4459 // Loop over the {lhs} and {rhs} strings to see if they are equal. | |
4460 Variable var_offset(assembler, MachineType::PointerRepresentation()); | |
4461 Label loop(assembler, &var_offset); | |
4462 var_offset.Bind(begin); | |
4463 assembler->Goto(&loop); | |
4464 assembler->Bind(&loop); | |
4465 { | |
4466 // Check if {offset} equals {end}. | |
4467 Node* offset = var_offset.value(); | |
4468 Label if_done(assembler), if_notdone(assembler); | |
4469 assembler->Branch(assembler->WordEqual(offset, end), &if_done, | |
4470 &if_notdone); | |
4471 | |
4472 assembler->Bind(&if_notdone); | |
4473 { | |
4474 // Load the next characters from {lhs} and {rhs}. | |
4475 Node* lhs_value = | |
4476 assembler->Load(MachineType::Uint8(), lhs, offset); | |
4477 Node* rhs_value = | |
4478 assembler->Load(MachineType::Uint8(), rhs, offset); | |
4479 | |
4480 // Check if the characters match. | |
4481 Label if_valueissame(assembler), if_valueisnotsame(assembler); | |
4482 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), | |
4483 &if_valueissame, &if_valueisnotsame); | |
4484 | |
4485 assembler->Bind(&if_valueissame); | |
4486 { | |
4487 // Advance to next character. | |
4488 var_offset.Bind( | |
4489 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | |
4490 } | |
4491 assembler->Goto(&loop); | |
4492 | |
4493 assembler->Bind(&if_valueisnotsame); | |
4494 assembler->Goto(&if_notequal); | |
4495 } | |
4496 | |
4497 assembler->Bind(&if_done); | |
4498 assembler->Goto(&if_equal); | |
4499 } | |
4500 } | |
4501 | |
4502 assembler->Bind(&if_notbothonebyteseqstrings); | |
4503 { | |
4504 // TODO(bmeurer): Add fast case support for flattened cons strings; | |
4505 // also add support for two byte string equality checks. | |
4506 Runtime::FunctionId function_id = (mode == kDontNegateResult) | |
4507 ? Runtime::kStringEqual | |
4508 : Runtime::kStringNotEqual; | |
4509 assembler->TailCallRuntime(function_id, context, lhs, rhs); | |
4510 } | |
4511 } | |
4512 } | |
4513 | |
4514 assembler->Bind(&if_lengthisnotequal); | |
4515 { | |
4516 // Mismatch in length of {lhs} and {rhs}, cannot be equal. | |
4517 assembler->Goto(&if_notequal); | |
4518 } | |
4519 } | |
4520 | |
4521 assembler->Bind(&if_equal); | |
4522 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); | |
4523 | |
4524 assembler->Bind(&if_notequal); | |
4525 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); | |
4526 } | |
4527 | |
4528 } // namespace | 4169 } // namespace |
4529 | 4170 |
4530 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 4171 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
4531 typedef compiler::Node Node; | 4172 typedef compiler::Node Node; |
4532 Node* context = assembler->Parameter(Descriptor::kContext); | 4173 Node* context = assembler->Parameter(Descriptor::kContext); |
4533 Node* receiver = assembler->Parameter(Descriptor::kReceiver); | 4174 Node* receiver = assembler->Parameter(Descriptor::kReceiver); |
4534 // For now we only support receiver_is_holder. | 4175 // For now we only support receiver_is_holder. |
4535 DCHECK(receiver_is_holder()); | 4176 DCHECK(receiver_is_holder()); |
4536 Node* holder = receiver; | 4177 Node* holder = receiver; |
4537 Node* map = assembler->LoadMap(receiver); | 4178 Node* map = assembler->LoadMap(receiver); |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4816 } | 4457 } |
4817 | 4458 |
4818 // static | 4459 // static |
4819 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, | 4460 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, |
4820 compiler::Node* lhs, | 4461 compiler::Node* lhs, |
4821 compiler::Node* rhs, | 4462 compiler::Node* rhs, |
4822 compiler::Node* context) { | 4463 compiler::Node* context) { |
4823 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); | 4464 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); |
4824 } | 4465 } |
4825 | 4466 |
4826 void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
4827 GenerateStringEqual(assembler, kDontNegateResult); | |
4828 } | |
4829 | |
4830 void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
4831 GenerateStringEqual(assembler, kNegateResult); | |
4832 } | |
4833 | |
4834 void StringLessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
4835 GenerateStringRelationalComparison(assembler, kLessThan); | |
4836 } | |
4837 | |
4838 void StringLessThanOrEqualStub::GenerateAssembly( | |
4839 CodeStubAssembler* assembler) const { | |
4840 GenerateStringRelationalComparison(assembler, kLessThanOrEqual); | |
4841 } | |
4842 | |
4843 void StringGreaterThanStub::GenerateAssembly( | |
4844 CodeStubAssembler* assembler) const { | |
4845 GenerateStringRelationalComparison(assembler, kGreaterThan); | |
4846 } | |
4847 | |
4848 void StringGreaterThanOrEqualStub::GenerateAssembly( | |
4849 CodeStubAssembler* assembler) const { | |
4850 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual); | |
4851 } | |
4852 | |
4853 void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 4467 void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
4854 typedef CodeStubAssembler::Label Label; | 4468 typedef CodeStubAssembler::Label Label; |
4855 typedef compiler::Node Node; | 4469 typedef compiler::Node Node; |
4856 typedef CodeStubAssembler::Variable Variable; | 4470 typedef CodeStubAssembler::Variable Variable; |
4857 | 4471 |
4858 Node* context = assembler->Parameter(1); | 4472 Node* context = assembler->Parameter(1); |
4859 | 4473 |
4860 // We might need to loop once for ToNumber conversion. | 4474 // We might need to loop once for ToNumber conversion. |
4861 Variable var_len(assembler, MachineRepresentation::kTagged); | 4475 Variable var_len(assembler, MachineRepresentation::kTagged); |
4862 Label loop(assembler, &var_len); | 4476 Label loop(assembler, &var_len); |
(...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6261 | 5875 |
6262 if (type == MachineType::Pointer()) { | 5876 if (type == MachineType::Pointer()) { |
6263 return Representation::External(); | 5877 return Representation::External(); |
6264 } | 5878 } |
6265 | 5879 |
6266 return Representation::Tagged(); | 5880 return Representation::Tagged(); |
6267 } | 5881 } |
6268 | 5882 |
6269 } // namespace internal | 5883 } // namespace internal |
6270 } // namespace v8 | 5884 } // namespace v8 |
OLD | NEW |