OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 4251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4262 __ cmp(boilerplate.reg(), Factory::undefined_value()); | 4262 __ cmp(boilerplate.reg(), Factory::undefined_value()); |
4263 deferred->Branch(equal); | 4263 deferred->Branch(equal); |
4264 deferred->BindExit(); | 4264 deferred->BindExit(); |
4265 literals.Unuse(); | 4265 literals.Unuse(); |
4266 | 4266 |
4267 // Push the boilerplate object. | 4267 // Push the boilerplate object. |
4268 frame_->Push(&boilerplate); | 4268 frame_->Push(&boilerplate); |
4269 } | 4269 } |
4270 | 4270 |
4271 | 4271 |
4272 // Materialize the object literal 'node' in the literals array | |
4273 // 'literals' of the function. Leave the object boilerplate in | |
4274 // 'boilerplate'. | |
4275 class DeferredObjectLiteral: public DeferredCode { | |
4276 public: | |
4277 DeferredObjectLiteral(Register boilerplate, | |
4278 Register literals, | |
4279 ObjectLiteral* node) | |
4280 : boilerplate_(boilerplate), literals_(literals), node_(node) { | |
4281 set_comment("[ DeferredObjectLiteral"); | |
4282 } | |
4283 | |
4284 void Generate(); | |
4285 | |
4286 private: | |
4287 Register boilerplate_; | |
4288 Register literals_; | |
4289 ObjectLiteral* node_; | |
4290 }; | |
4291 | |
4292 | |
4293 void DeferredObjectLiteral::Generate() { | |
4294 // Since the entry is undefined we call the runtime system to | |
4295 // compute the literal. | |
4296 // Literal array (0). | |
4297 __ push(literals_); | |
4298 // Literal index (1). | |
4299 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | |
4300 // Constant properties (2). | |
4301 __ push(Immediate(node_->constant_properties())); | |
4302 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | |
4303 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); | |
4304 } | |
4305 | |
4306 | |
4307 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 4272 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
4308 Comment cmnt(masm_, "[ ObjectLiteral"); | 4273 Comment cmnt(masm_, "[ ObjectLiteral"); |
4309 | 4274 |
4310 // Retrieve the literals array and check the allocated entry. Begin | 4275 // Load a writable copy of the function of this activation in a |
4311 // with a writable copy of the function of this activation in a | |
4312 // register. | 4276 // register. |
4313 frame_->PushFunction(); | 4277 frame_->PushFunction(); |
4314 Result literals = frame_->Pop(); | 4278 Result literals = frame_->Pop(); |
4315 literals.ToRegister(); | 4279 literals.ToRegister(); |
4316 frame_->Spill(literals.reg()); | 4280 frame_->Spill(literals.reg()); |
4317 | 4281 |
4318 // Load the literals array of the function. | 4282 // Load the literals array of the function. |
4319 __ mov(literals.reg(), | 4283 __ mov(literals.reg(), |
4320 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 4284 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
4321 | 4285 // Literal array. |
4322 // Load the literal at the ast saved index. | 4286 frame_->Push(&literals); |
4323 Result boilerplate = allocator_->Allocate(); | 4287 // Literal index. |
4324 ASSERT(boilerplate.is_valid()); | 4288 frame_->Push(Smi::FromInt(node->literal_index())); |
4325 int literal_offset = | 4289 // Constant properties. |
4326 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 4290 frame_->Push(node->constant_properties()); |
4327 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); | 4291 Result clone; |
4328 | 4292 if (node->depth() > 1) { |
4329 // Check whether we need to materialize the object literal boilerplate. | 4293 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); |
4330 // If so, jump to the deferred code passing the literals array. | 4294 } else { |
4331 DeferredObjectLiteral* deferred = | 4295 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); |
4332 new DeferredObjectLiteral(boilerplate.reg(), literals.reg(), node); | |
4333 __ cmp(boilerplate.reg(), Factory::undefined_value()); | |
4334 deferred->Branch(equal); | |
4335 deferred->BindExit(); | |
4336 literals.Unuse(); | |
4337 | |
4338 // Push the boilerplate object. | |
4339 frame_->Push(&boilerplate); | |
4340 // Clone the boilerplate object. | |
4341 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate; | |
4342 if (node->depth() == 1) { | |
4343 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate; | |
4344 } | 4296 } |
4345 Result clone = frame_->CallRuntime(clone_function_id, 1); | |
4346 // Push the newly cloned literal object as the result. | |
4347 frame_->Push(&clone); | 4297 frame_->Push(&clone); |
4348 | 4298 |
4349 for (int i = 0; i < node->properties()->length(); i++) { | 4299 for (int i = 0; i < node->properties()->length(); i++) { |
4350 ObjectLiteral::Property* property = node->properties()->at(i); | 4300 ObjectLiteral::Property* property = node->properties()->at(i); |
4351 switch (property->kind()) { | 4301 switch (property->kind()) { |
4352 case ObjectLiteral::Property::CONSTANT: | 4302 case ObjectLiteral::Property::CONSTANT: |
4353 break; | 4303 break; |
4354 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 4304 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
4355 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 4305 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; |
4356 // else fall through. | 4306 // else fall through. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4396 Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 4346 Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
4397 // Ignore the result. | 4347 // Ignore the result. |
4398 break; | 4348 break; |
4399 } | 4349 } |
4400 default: UNREACHABLE(); | 4350 default: UNREACHABLE(); |
4401 } | 4351 } |
4402 } | 4352 } |
4403 } | 4353 } |
4404 | 4354 |
4405 | 4355 |
4406 // Materialize the array literal 'node' in the literals array 'literals' | |
4407 // of the function. Leave the array boilerplate in 'boilerplate'. | |
4408 class DeferredArrayLiteral: public DeferredCode { | |
4409 public: | |
4410 DeferredArrayLiteral(Register boilerplate, | |
4411 Register literals, | |
4412 ArrayLiteral* node) | |
4413 : boilerplate_(boilerplate), literals_(literals), node_(node) { | |
4414 set_comment("[ DeferredArrayLiteral"); | |
4415 } | |
4416 | |
4417 void Generate(); | |
4418 | |
4419 private: | |
4420 Register boilerplate_; | |
4421 Register literals_; | |
4422 ArrayLiteral* node_; | |
4423 }; | |
4424 | |
4425 | |
4426 void DeferredArrayLiteral::Generate() { | |
4427 // Since the entry is undefined we call the runtime system to | |
4428 // compute the literal. | |
4429 // Literal array (0). | |
4430 __ push(literals_); | |
4431 // Literal index (1). | |
4432 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | |
4433 // Constant properties (2). | |
4434 __ push(Immediate(node_->literals())); | |
4435 __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3); | |
4436 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); | |
4437 } | |
4438 | |
4439 | |
4440 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 4356 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
4441 Comment cmnt(masm_, "[ ArrayLiteral"); | 4357 Comment cmnt(masm_, "[ ArrayLiteral"); |
4442 | 4358 |
4443 // Retrieve the literals array and check the allocated entry. Begin | 4359 // Load a writable copy of the function of this activation in a |
4444 // with a writable copy of the function of this activation in a | |
4445 // register. | 4360 // register. |
4446 frame_->PushFunction(); | 4361 frame_->PushFunction(); |
4447 Result literals = frame_->Pop(); | 4362 Result literals = frame_->Pop(); |
4448 literals.ToRegister(); | 4363 literals.ToRegister(); |
4449 frame_->Spill(literals.reg()); | 4364 frame_->Spill(literals.reg()); |
4450 | 4365 |
4451 // Load the literals array of the function. | 4366 // Load the literals array of the function. |
4452 __ mov(literals.reg(), | 4367 __ mov(literals.reg(), |
4453 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 4368 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
4454 | 4369 |
4455 // Load the literal at the ast saved index. | 4370 frame_->Push(&literals); |
4456 Result boilerplate = allocator_->Allocate(); | 4371 frame_->Push(Smi::FromInt(node->literal_index())); |
4457 ASSERT(boilerplate.is_valid()); | 4372 frame_->Push(node->constant_elements()); |
4458 int literal_offset = | |
4459 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | |
4460 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); | |
4461 | |
4462 // Check whether we need to materialize the object literal boilerplate. | |
4463 // If so, jump to the deferred code passing the literals array. | |
4464 DeferredArrayLiteral* deferred = | |
4465 new DeferredArrayLiteral(boilerplate.reg(), literals.reg(), node); | |
4466 __ cmp(boilerplate.reg(), Factory::undefined_value()); | |
4467 deferred->Branch(equal); | |
4468 deferred->BindExit(); | |
4469 literals.Unuse(); | |
4470 | |
4471 // Push the resulting array literal boilerplate on the stack. | |
4472 frame_->Push(&boilerplate); | |
4473 | |
4474 // Clone the boilerplate object. | |
4475 int length = node->values()->length(); | 4373 int length = node->values()->length(); |
4476 Result clone; | 4374 Result clone; |
4477 if (node->depth() == 1) { | 4375 if (node->depth() > 1) { |
4478 if (length <= FastCloneShallowArrayStub::kMaximumLength) { | 4376 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); |
4479 FastCloneShallowArrayStub stub(length); | 4377 } else if (length > FastCloneShallowArrayStub::kMaximumLength) { |
4480 clone = frame_->CallStub(&stub, 1); | 4378 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
4481 } else { | |
4482 clone = frame_->CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); | |
4483 } | |
4484 } else { | 4379 } else { |
4485 clone = frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); | 4380 FastCloneShallowArrayStub stub(length); |
| 4381 clone = frame_->CallStub(&stub, 3); |
4486 } | 4382 } |
4487 // Push the newly cloned literal object as the result. | |
4488 frame_->Push(&clone); | 4383 frame_->Push(&clone); |
4489 | 4384 |
4490 // Generate code to set the elements in the array that are not | 4385 // Generate code to set the elements in the array that are not |
4491 // literals. | 4386 // literals. |
4492 for (int i = 0; i < length; i++) { | 4387 for (int i = 0; i < length; i++) { |
4493 Expression* value = node->values()->at(i); | 4388 Expression* value = node->values()->at(i); |
4494 | 4389 |
4495 // If value is a literal the property value is already set in the | 4390 // If value is a literal the property value is already set in the |
4496 // boilerplate object. | 4391 // boilerplate object. |
4497 if (value->AsLiteral() != NULL) continue; | 4392 if (value->AsLiteral() != NULL) continue; |
(...skipping 2260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6758 // Need to collect. Call into runtime system. | 6653 // Need to collect. Call into runtime system. |
6759 __ bind(&gc); | 6654 __ bind(&gc); |
6760 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); | 6655 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); |
6761 } | 6656 } |
6762 | 6657 |
6763 | 6658 |
6764 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 6659 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
6765 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; | 6660 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; |
6766 int size = JSArray::kSize + elements_size; | 6661 int size = JSArray::kSize + elements_size; |
6767 | 6662 |
| 6663 // Load boilerplate object into ecx and check if we need to create a |
| 6664 // boilerplate. |
| 6665 __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
| 6666 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
| 6667 ASSERT(kPointerSize == 4); |
| 6668 __ mov(ecx, FieldOperand(ecx, |
| 6669 eax, |
| 6670 times_2, |
| 6671 FixedArray::kHeaderSize)); |
| 6672 __ cmp(ecx, Factory::undefined_value()); |
| 6673 Label slow_case; |
| 6674 __ j(equal, &slow_case); |
| 6675 |
| 6676 |
6768 // Allocate both the JS array and the elements array in one big | 6677 // Allocate both the JS array and the elements array in one big |
6769 // allocation. This avoid multiple limit checks. | 6678 // allocation. This avoids multiple limit checks. |
6770 Label gc; | 6679 __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); |
6771 __ AllocateInNewSpace(size, eax, ebx, ecx, &gc, TAG_OBJECT); | |
6772 | |
6773 // Get the boilerplate from the stack. | |
6774 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | |
6775 | 6680 |
6776 // Copy the JS array part. | 6681 // Copy the JS array part. |
6777 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { | 6682 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
6778 if ((i != JSArray::kElementsOffset) || (length_ == 0)) { | 6683 if ((i != JSArray::kElementsOffset) || (length_ == 0)) { |
6779 __ mov(ebx, FieldOperand(ecx, i)); | 6684 __ mov(ebx, FieldOperand(ecx, i)); |
6780 __ mov(FieldOperand(eax, i), ebx); | 6685 __ mov(FieldOperand(eax, i), ebx); |
6781 } | 6686 } |
6782 } | 6687 } |
6783 | 6688 |
6784 if (length_ > 0) { | 6689 if (length_ > 0) { |
6785 // Get hold of the elements array of the boilerplate and setup the | 6690 // Get hold of the elements array of the boilerplate and setup the |
6786 // elements pointer in the resulting object. | 6691 // elements pointer in the resulting object. |
6787 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); | 6692 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
6788 __ lea(edx, Operand(eax, JSArray::kSize)); | 6693 __ lea(edx, Operand(eax, JSArray::kSize)); |
6789 __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); | 6694 __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); |
6790 | 6695 |
6791 // Copy the elements array. | 6696 // Copy the elements array. |
6792 for (int i = 0; i < elements_size; i += kPointerSize) { | 6697 for (int i = 0; i < elements_size; i += kPointerSize) { |
6793 __ mov(ebx, FieldOperand(ecx, i)); | 6698 __ mov(ebx, FieldOperand(ecx, i)); |
6794 __ mov(FieldOperand(edx, i), ebx); | 6699 __ mov(FieldOperand(edx, i), ebx); |
6795 } | 6700 } |
6796 } | 6701 } |
6797 | 6702 |
6798 // Return and remove the on-stack parameter. | 6703 // Return and remove the on-stack parameters. |
6799 __ ret(1 * kPointerSize); | 6704 __ ret(3 * kPointerSize); |
6800 | 6705 |
6801 __ bind(&gc); | 6706 __ bind(&slow_case); |
6802 ExternalReference runtime(Runtime::kCloneShallowLiteralBoilerplate); | 6707 ExternalReference runtime(Runtime::kCreateArrayLiteralShallow); |
6803 __ TailCallRuntime(runtime, 1, 1); | 6708 __ TailCallRuntime(runtime, 3, 1); |
6804 } | 6709 } |
6805 | 6710 |
6806 | 6711 |
6807 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). | 6712 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). |
6808 void ToBooleanStub::Generate(MacroAssembler* masm) { | 6713 void ToBooleanStub::Generate(MacroAssembler* masm) { |
6809 Label false_result, true_result, not_string; | 6714 Label false_result, true_result, not_string; |
6810 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 6715 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
6811 | 6716 |
6812 // 'null' => false. | 6717 // 'null' => false. |
6813 __ cmp(eax, Factory::null_value()); | 6718 __ cmp(eax, Factory::null_value()); |
(...skipping 2185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8999 __ add(Operand(dest), Immediate(2)); | 8904 __ add(Operand(dest), Immediate(2)); |
9000 } | 8905 } |
9001 __ sub(Operand(count), Immediate(1)); | 8906 __ sub(Operand(count), Immediate(1)); |
9002 __ j(not_zero, &loop); | 8907 __ j(not_zero, &loop); |
9003 } | 8908 } |
9004 | 8909 |
9005 | 8910 |
9006 #undef __ | 8911 #undef __ |
9007 | 8912 |
9008 } } // namespace v8::internal | 8913 } } // namespace v8::internal |
OLD | NEW |