| Index: src/codegen-ia32.cc
|
| ===================================================================
|
| --- src/codegen-ia32.cc (revision 1544)
|
| +++ src/codegen-ia32.cc (working copy)
|
| @@ -32,6 +32,7 @@
|
| #include "debug.h"
|
| #include "scopes.h"
|
| #include "runtime.h"
|
| +#include "parser.h"
|
|
|
| namespace v8 { namespace internal {
|
|
|
| @@ -3499,15 +3500,22 @@
|
| // Push the boilerplate object.
|
| frame_->Push(&boilerplate);
|
| // Clone the boilerplate object.
|
| - Result clone =
|
| - frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
|
| + Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
|
| + if (node->depth() == 1) {
|
| + clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
|
| + }
|
| + Result clone = frame_->CallRuntime(clone_function_id, 1);
|
| // Push the newly cloned literal object as the result.
|
| frame_->Push(&clone);
|
|
|
| for (int i = 0; i < node->properties()->length(); i++) {
|
| ObjectLiteral::Property* property = node->properties()->at(i);
|
| switch (property->kind()) {
|
| - case ObjectLiteral::Property::CONSTANT: break;
|
| + case ObjectLiteral::Property::CONSTANT:
|
| + break;
|
| + case ObjectLiteral::Property::MATERIALIZED_LITERAL:
|
| + if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
|
| + // else fall through.
|
| case ObjectLiteral::Property::COMPUTED: {
|
| Handle<Object> key(property->key()->handle());
|
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| @@ -3565,59 +3573,126 @@
|
| }
|
|
|
|
|
| +// This deferred code stub will be used for creating the boilerplate
|
| +// by calling Runtime_CreateArrayLiteralBoilerplate.
|
| +// Each created boilerplate is stored in the JSFunction and they are
|
| +// therefore context dependent.
|
| +class DeferredArrayLiteral: public DeferredCode {
|
| + public:
|
| + DeferredArrayLiteral(CodeGenerator* generator,
|
| + ArrayLiteral* node)
|
| + : DeferredCode(generator), node_(node) {
|
| + set_comment("[ DeferredArrayLiteral");
|
| + }
|
| +
|
| + virtual void Generate();
|
| +
|
| + private:
|
| + ArrayLiteral* node_;
|
| +};
|
| +
|
| +
|
| +void DeferredArrayLiteral::Generate() {
|
| + Result literals(generator());
|
| + enter()->Bind(&literals);
|
| + // Since the entry is undefined we call the runtime system to
|
| + // compute the literal.
|
| +
|
| + VirtualFrame* frame = generator()->frame();
|
| + // Literal array (0).
|
| + frame->Push(&literals);
|
| + // Literal index (1).
|
| + frame->Push(Smi::FromInt(node_->literal_index()));
|
| + // Constant properties (2).
|
| + frame->Push(node_->literals());
|
| + Result boilerplate =
|
| + frame->CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
|
| + exit_.Jump(&boilerplate);
|
| +}
|
| +
|
| +
|
| void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
|
| Comment cmnt(masm_, "[ ArrayLiteral");
|
| + DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node);
|
|
|
| - // Call the runtime to create the array literal.
|
| - frame_->Push(node->literals());
|
| - // Load the literals array of the current function.
|
| + // Retrieve the literals array and check the allocated entry. Begin
|
| + // with a writable copy of the function of this activation in a
|
| + // register.
|
| frame_->PushFunction();
|
| Result literals = frame_->Pop();
|
| literals.ToRegister();
|
| - frame_->Spill(literals.reg()); // Make it writable.
|
| + frame_->Spill(literals.reg());
|
| +
|
| + // Load the literals array of the function.
|
| __ mov(literals.reg(),
|
| FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
|
| - frame_->Push(&literals);
|
| - Result array = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
|
|
|
| + // Load the literal at the ast saved index.
|
| + int literal_offset =
|
| + FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
|
| + Result boilerplate = allocator_->Allocate();
|
| + ASSERT(boilerplate.is_valid());
|
| + __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
|
| +
|
| + // Check whether we need to materialize the object literal boilerplate.
|
| + // If so, jump to the deferred code passing the literals array.
|
| + __ cmp(boilerplate.reg(), Factory::undefined_value());
|
| + deferred->enter()->Branch(equal, &literals, not_taken);
|
| +
|
| + literals.Unuse();
|
| + // The deferred code returns the boilerplate object.
|
| + deferred->BindExit(&boilerplate);
|
| +
|
| // Push the resulting array literal on the stack.
|
| - frame_->Push(&array);
|
| + frame_->Push(&boilerplate);
|
|
|
| + // Clone the boilerplate object.
|
| + Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
|
| + if (node->depth() == 1) {
|
| + clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
|
| + }
|
| + Result clone = frame_->CallRuntime(clone_function_id, 1);
|
| + // Push the newly cloned literal object as the result.
|
| + frame_->Push(&clone);
|
| +
|
| // Generate code to set the elements in the array that are not
|
| // literals.
|
| for (int i = 0; i < node->values()->length(); i++) {
|
| Expression* value = node->values()->at(i);
|
|
|
| - // If value is literal the property value is already set in the
|
| + // If value is a literal the property value is already set in the
|
| // boilerplate object.
|
| - if (value->AsLiteral() == NULL) {
|
| - // The property must be set by generated code.
|
| - Load(value);
|
| + if (value->AsLiteral() != NULL) continue;
|
| + // If value is a materialized literal the property value is already set
|
| + // in the boilerplate object if it is simple.
|
| + if (CompileTimeValue::IsCompileTimeValue(value)) continue;
|
|
|
| - // Get the property value off the stack.
|
| - Result prop_value = frame_->Pop();
|
| - prop_value.ToRegister();
|
| + // The property must be set by generated code.
|
| + Load(value);
|
|
|
| - // Fetch the array literal while leaving a copy on the stack and
|
| - // use it to get the elements array.
|
| - frame_->Dup();
|
| - Result elements = frame_->Pop();
|
| - elements.ToRegister();
|
| - frame_->Spill(elements.reg());
|
| - // Get the elements array.
|
| - __ mov(elements.reg(),
|
| - FieldOperand(elements.reg(), JSObject::kElementsOffset));
|
| + // Get the property value off the stack.
|
| + Result prop_value = frame_->Pop();
|
| + prop_value.ToRegister();
|
|
|
| - // Write to the indexed properties array.
|
| - int offset = i * kPointerSize + Array::kHeaderSize;
|
| - __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
|
| + // Fetch the array literal while leaving a copy on the stack and
|
| + // use it to get the elements array.
|
| + frame_->Dup();
|
| + Result elements = frame_->Pop();
|
| + elements.ToRegister();
|
| + frame_->Spill(elements.reg());
|
| + // Get the elements array.
|
| + __ mov(elements.reg(),
|
| + FieldOperand(elements.reg(), JSObject::kElementsOffset));
|
|
|
| - // Update the write barrier for the array address.
|
| - frame_->Spill(prop_value.reg()); // Overwritten by the write barrier.
|
| - Result scratch = allocator_->Allocate();
|
| - ASSERT(scratch.is_valid());
|
| - __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
|
| - }
|
| + // Write to the indexed properties array.
|
| + int offset = i * kPointerSize + Array::kHeaderSize;
|
| + __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
|
| +
|
| + // Update the write barrier for the array address.
|
| + frame_->Spill(prop_value.reg()); // Overwritten by the write barrier.
|
| + Result scratch = allocator_->Allocate();
|
| + ASSERT(scratch.is_valid());
|
| + __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
|
| }
|
| }
|
|
|
|
|