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