Commit 3aa57f7f authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Revert 1432, 1433, 1469 and 1472 due to a bug with literal objects.

Review URL: http://codereview.chromium.org/46088

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1511 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 46f753a1
...@@ -135,12 +135,8 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) { ...@@ -135,12 +135,8 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) {
Object* k = *key->handle(); Object* k = *key->handle();
if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) { if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
kind_ = PROTOTYPE; kind_ = PROTOTYPE;
} else if (value_->AsMaterializedLiteral() != NULL) {
kind_ = MATERIALIZED_LITERAL;
} else if (value_->AsLiteral() != NULL) {
kind_ = CONSTANT;
} else { } else {
kind_ = COMPUTED; kind_ = value_->AsLiteral() == NULL ? COMPUTED : CONSTANT;
} }
} }
......
...@@ -95,7 +95,6 @@ namespace v8 { namespace internal { ...@@ -95,7 +95,6 @@ namespace v8 { namespace internal {
// Forward declarations // Forward declarations
class TargetCollector; class TargetCollector;
class MaterializedLiteral;
#define DEF_FORWARD_DECLARATION(type) class type; #define DEF_FORWARD_DECLARATION(type) class type;
NODE_LIST(DEF_FORWARD_DECLARATION) NODE_LIST(DEF_FORWARD_DECLARATION)
...@@ -130,9 +129,6 @@ class Node: public ZoneObject { ...@@ -130,9 +129,6 @@ class Node: public ZoneObject {
virtual BinaryOperation* AsBinaryOperation() { return NULL; } virtual BinaryOperation* AsBinaryOperation() { return NULL; }
virtual Assignment* AsAssignment() { return NULL; } virtual Assignment* AsAssignment() { return NULL; }
virtual FunctionLiteral* AsFunctionLiteral() { return NULL; } virtual FunctionLiteral* AsFunctionLiteral() { return NULL; }
virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
virtual ObjectLiteral* AsObjectLiteral() { return NULL; }
virtual ArrayLiteral* AsArrayLiteral() { return NULL; }
void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; } void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
int statement_pos() const { return statement_pos_; } int statement_pos() const { return statement_pos_; }
...@@ -640,20 +636,11 @@ class Literal: public Expression { ...@@ -640,20 +636,11 @@ class Literal: public Expression {
// Base class for literals that needs space in the corresponding JSFunction. // Base class for literals that needs space in the corresponding JSFunction.
class MaterializedLiteral: public Expression { class MaterializedLiteral: public Expression {
public: public:
explicit MaterializedLiteral(int literal_index, bool is_simple) explicit MaterializedLiteral(int literal_index)
: literal_index_(literal_index), is_simple_(is_simple) {} : literal_index_(literal_index) {}
virtual MaterializedLiteral* AsMaterializedLiteral() { return this; }
int literal_index() { return literal_index_; } int literal_index() { return literal_index_; }
// A materialized literal is simple if the values consist of only
// constants and simple object and array literals.
bool is_simple() const { return is_simple_; }
private: private:
int literal_index_; int literal_index_;
bool is_simple_;
}; };
...@@ -668,11 +655,10 @@ class ObjectLiteral: public MaterializedLiteral { ...@@ -668,11 +655,10 @@ class ObjectLiteral: public MaterializedLiteral {
public: public:
enum Kind { enum Kind {
CONSTANT, // Property with constant value (compile time). CONSTANT, // Property with constant value (at compile time).
COMPUTED, // Property with computed value (execution time). COMPUTED, // Property with computed value (at execution time).
MATERIALIZED_LITERAL, // Property value is a materialized literal. GETTER, SETTER, // Property is an accessor function.
GETTER, SETTER, // Property is an accessor function. PROTOTYPE // Property is __proto__.
PROTOTYPE // Property is __proto__.
}; };
Property(Literal* key, Expression* value); Property(Literal* key, Expression* value);
...@@ -690,13 +676,12 @@ class ObjectLiteral: public MaterializedLiteral { ...@@ -690,13 +676,12 @@ class ObjectLiteral: public MaterializedLiteral {
ObjectLiteral(Handle<FixedArray> constant_properties, ObjectLiteral(Handle<FixedArray> constant_properties,
ZoneList<Property*>* properties, ZoneList<Property*>* properties,
int literal_index, int literal_index)
bool is_simple) : MaterializedLiteral(literal_index),
: MaterializedLiteral(literal_index, is_simple),
constant_properties_(constant_properties), constant_properties_(constant_properties),
properties_(properties) {} properties_(properties) {
}
virtual ObjectLiteral* AsObjectLiteral() { return this; }
virtual void Accept(AstVisitor* v); virtual void Accept(AstVisitor* v);
Handle<FixedArray> constant_properties() const { Handle<FixedArray> constant_properties() const {
...@@ -716,7 +701,7 @@ class RegExpLiteral: public MaterializedLiteral { ...@@ -716,7 +701,7 @@ class RegExpLiteral: public MaterializedLiteral {
RegExpLiteral(Handle<String> pattern, RegExpLiteral(Handle<String> pattern,
Handle<String> flags, Handle<String> flags,
int literal_index) int literal_index)
: MaterializedLiteral(literal_index, false), : MaterializedLiteral(literal_index),
pattern_(pattern), pattern_(pattern),
flags_(flags) {} flags_(flags) {}
...@@ -732,18 +717,14 @@ class RegExpLiteral: public MaterializedLiteral { ...@@ -732,18 +717,14 @@ class RegExpLiteral: public MaterializedLiteral {
// An array literal has a literals object that is used // An array literal has a literals object that is used
// for minimizing the work when constructing it at runtime. // for minimizing the work when constructing it at runtime.
class ArrayLiteral: public MaterializedLiteral { class ArrayLiteral: public Expression {
public: public:
ArrayLiteral(Handle<FixedArray> literals, ArrayLiteral(Handle<FixedArray> literals,
ZoneList<Expression*>* values, ZoneList<Expression*>* values)
int literal_index, : literals_(literals), values_(values) {
bool is_simple) }
: MaterializedLiteral(literal_index, is_simple),
literals_(literals),
values_(values) {}
virtual void Accept(AstVisitor* v); virtual void Accept(AstVisitor* v);
virtual ArrayLiteral* AsArrayLiteral() { return this; }
Handle<FixedArray> literals() const { return literals_; } Handle<FixedArray> literals() const { return literals_; }
ZoneList<Expression*>* values() const { return values_; } ZoneList<Expression*>* values() const { return values_; }
......
...@@ -2612,7 +2612,7 @@ void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { ...@@ -2612,7 +2612,7 @@ void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
// This deferred code stub will be used for creating the boilerplate // This deferred code stub will be used for creating the boilerplate
// by calling Runtime_CreateObjectLiteralBoilerplate. // by calling Runtime_CreateObjectLiteral.
// Each created boilerplate is stored in the JSFunction and they are // Each created boilerplate is stored in the JSFunction and they are
// therefore context dependent. // therefore context dependent.
class DeferredObjectLiteral: public DeferredCode { class DeferredObjectLiteral: public DeferredCode {
...@@ -2686,7 +2686,7 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { ...@@ -2686,7 +2686,7 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
frame_->EmitPush(r2); frame_->EmitPush(r2);
// Clone the boilerplate object. // Clone the boilerplate object.
frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
frame_->EmitPush(r0); // save the result frame_->EmitPush(r0); // save the result
// r0: cloned object literal // r0: cloned object literal
...@@ -2695,11 +2695,7 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { ...@@ -2695,11 +2695,7 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
Literal* key = property->key(); Literal* key = property->key();
Expression* value = property->value(); Expression* value = property->value();
switch (property->kind()) { switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT: case ObjectLiteral::Property::CONSTANT: break;
break;
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
if (property->value()->AsMaterializedLiteral()->is_simple()) break;
// else fall through
case ObjectLiteral::Property::COMPUTED: // fall through case ObjectLiteral::Property::COMPUTED: // fall through
case ObjectLiteral::Property::PROTOTYPE: { case ObjectLiteral::Property::PROTOTYPE: {
frame_->EmitPush(r0); // dup the result frame_->EmitPush(r0); // dup the result
...@@ -2736,49 +2732,6 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { ...@@ -2736,49 +2732,6 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
} }
// 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() {
// Argument is passed in r1.
enter()->Bind();
VirtualFrame::SpilledScope spilled_scope(generator());
// If the entry is undefined we call the runtime system to computed
// the literal.
VirtualFrame* frame = generator()->frame();
// Literal array (0).
frame->EmitPush(r1);
// Literal index (1).
__ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
frame->EmitPush(r0);
// Constant properties (2).
__ mov(r0, Operand(node_->literals()));
frame->EmitPush(r0);
Result boilerplate =
frame->CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
__ mov(r2, Operand(boilerplate.reg()));
// Result is returned in r2.
exit_.Jump();
}
void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
#ifdef DEBUG #ifdef DEBUG
int original_height = frame_->height(); int original_height = frame_->height();
...@@ -2786,34 +2739,17 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { ...@@ -2786,34 +2739,17 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
VirtualFrame::SpilledScope spilled_scope(this); VirtualFrame::SpilledScope spilled_scope(this);
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node); // Call runtime to create the array literal.
__ mov(r0, Operand(node->literals()));
// Retrieve the literal array and check the allocated entry. frame_->EmitPush(r0);
// Load the function of this frame.
// Load the function of this activation. __ ldr(r0, frame_->Function());
__ ldr(r1, frame_->Function()); __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
frame_->EmitPush(r0);
// Load the literals array of the function. frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
// Load the literal at the ast saved index.
int literal_offset =
FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
__ ldr(r2, FieldMemOperand(r1, literal_offset));
// Check whether we need to materialize the object literal boilerplate.
// If so, jump to the deferred code.
__ cmp(r2, Operand(Factory::undefined_value()));
deferred->enter()->Branch(eq);
deferred->BindExit();
// Push the object literal boilerplate.
frame_->EmitPush(r2);
// Clone the boilerplate object. // Push the resulting array literal on the stack.
frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); frame_->EmitPush(r0);
frame_->EmitPush(r0); // save the result
// r0: cloned object literal
// Generate code to set the elements in the array that are not // Generate code to set the elements in the array that are not
// literals. // literals.
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "debug.h" #include "debug.h"
#include "scopes.h" #include "scopes.h"
#include "runtime.h" #include "runtime.h"
#include "parser.h"
namespace v8 { namespace internal { namespace v8 { namespace internal {
...@@ -3501,18 +3500,14 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { ...@@ -3501,18 +3500,14 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
frame_->Push(&boilerplate); frame_->Push(&boilerplate);
// Clone the boilerplate object. // Clone the boilerplate object.
Result clone = Result clone =
frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
// Push the newly cloned literal object as the result. // Push the newly cloned literal object as the result.
frame_->Push(&clone); frame_->Push(&clone);
for (int i = 0; i < node->properties()->length(); i++) { for (int i = 0; i < node->properties()->length(); i++) {
ObjectLiteral::Property* property = node->properties()->at(i); ObjectLiteral::Property* property = node->properties()->at(i);
switch (property->kind()) { switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT: case ObjectLiteral::Property::CONSTANT: break;
break;
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
// else fall through.
case ObjectLiteral::Property::COMPUTED: { case ObjectLiteral::Property::COMPUTED: {
Handle<Object> key(property->key()->handle()); Handle<Object> key(property->key()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
...@@ -3570,123 +3565,59 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { ...@@ -3570,123 +3565,59 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
} }
// 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) { void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node);
// Retrieve the literals array and check the allocated entry. Begin // Call the runtime to create the array literal.
// with a writable copy of the function of this activation in a frame_->Push(node->literals());
// register. // Load the literals array of the current function.
frame_->PushFunction(); frame_->PushFunction();
Result literals = frame_->Pop(); Result literals = frame_->Pop();
literals.ToRegister(); literals.ToRegister();
frame_->Spill(literals.reg()); frame_->Spill(literals.reg()); // Make it writable.
// Load the literals array of the function.
__ mov(literals.reg(), __ mov(literals.reg(),
FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
frame_->Push(&literals);
// Load the literal at the ast saved index. Result array = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
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. // Push the resulting array literal on the stack.
frame_->Push(&boilerplate); frame_->Push(&array);
// Clone the boilerplate object.
Result clone =
frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 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 // Generate code to set the elements in the array that are not
// literals. // literals.
for (int i = 0; i < node->values()->length(); i++) { for (int i = 0; i < node->values()->length(); i++) {
Expression* value = node->values()->at(i); Expression* value = node->values()->at(i);
// If value is a literal the property value is already set in the // If value is literal the property value is already set in the
// boilerplate object. // boilerplate object.
if (value->AsLiteral() != NULL) continue; if (value->AsLiteral() == NULL) {
// If value is a materialized literal the property value is already set // The property must be set by generated code.
// in the boilerplate object if it is simple. Load(value);
if (CompileTimeValue::IsCompileTimeValue(value)) continue;
// The property must be set by generated code.
Load(value);
// Get the property value off the stack. // Get the property value off the stack.
Result prop_value = frame_->Pop(); Result prop_value = frame_->Pop();
prop_value.ToRegister(); prop_value.ToRegister();
// Fetch the array literal while leaving a copy on the stack and // Fetch the array literal while leaving a copy on the stack and
// use it to get the elements array. // use it to get the elements array.
frame_->Dup(); frame_->Dup();
Result elements = frame_->Pop(); Result elements = frame_->Pop();
elements.ToRegister(); elements.ToRegister();
frame_->Spill(elements.reg()); frame_->Spill(elements.reg());
// Get the elements array. // Get the elements array.
__ mov(elements.reg(), __ mov(elements.reg(),
FieldOperand(elements.reg(), JSObject::kElementsOffset)); FieldOperand(elements.reg(), JSObject::kElementsOffset));
// Write to the indexed properties array. // Write to the indexed properties array.
int offset = i * kPointerSize + Array::kHeaderSize; int offset = i * kPointerSize + Array::kHeaderSize;
__ mov(FieldOperand(elements.reg(), offset), prop_value.reg()); __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
// Update the write barrier for the array address. // Update the write barrier for the array address.
frame_->Spill(prop_value.reg()); // Overwritten by the write barrier. frame_->Spill(prop_value.reg()); // Overwritten by the write barrier.
Result scratch = allocator_->Allocate(); Result scratch = allocator_->Allocate();
ASSERT(scratch.is_valid()); ASSERT(scratch.is_valid());
__ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
}
} }
} }
......
...@@ -167,6 +167,8 @@ namespace v8 { namespace internal { ...@@ -167,6 +167,8 @@ namespace v8 { namespace internal {
V(char_at_symbol, "CharAt") \ V(char_at_symbol, "CharAt") \
V(undefined_symbol, "undefined") \ V(undefined_symbol, "undefined") \
V(value_of_symbol, "valueOf") \ V(value_of_symbol, "valueOf") \
V(CreateObjectLiteralBoilerplate_symbol, "CreateObjectLiteralBoilerplate") \
V(CreateArrayLiteral_symbol, "CreateArrayLiteral") \
V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \ V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \
V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \ V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \
V(stack_overflow_symbol, "kStackOverflowBoilerplate") \ V(stack_overflow_symbol, "kStackOverflowBoilerplate") \
......
...@@ -158,12 +158,10 @@ class Parser { ...@@ -158,12 +158,10 @@ class Parser {
// Decide if a property should be the object boilerplate. // Decide if a property should be the object boilerplate.
bool IsBoilerplateProperty(ObjectLiteral::Property* property); bool IsBoilerplateProperty(ObjectLiteral::Property* property);
// If the expression is a literal, return the literal value; // If the property is CONSTANT type, it returns the literal value,
// if the expression is a materialized literal and is simple return a // otherwise, it return undefined literal as the placeholder
// compile time value as encoded by CompileTimeValue::GetValue().
// Otherwise, return undefined literal as the placeholder
// in the object literal boilerplate. // in the object literal boilerplate.
Handle<Object> GetBoilerplateValue(Expression* expression); Literal* GetBoilerplateValue(ObjectLiteral::Property* property);
enum FunctionLiteralType { enum FunctionLiteralType {
EXPRESSION, EXPRESSION,
...@@ -3058,7 +3056,6 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { ...@@ -3058,7 +3056,6 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
// Update the scope information before the pre-parsing bailout. // Update the scope information before the pre-parsing bailout.
temp_scope_->set_contains_array_literal(); temp_scope_->set_contains_array_literal();
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
if (is_pre_parsing_) return NULL; if (is_pre_parsing_) return NULL;
...@@ -3067,19 +3064,16 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { ...@@ -3067,19 +3064,16 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
Factory::NewFixedArray(values.length(), TENURED); Factory::NewFixedArray(values.length(), TENURED);
// Fill in the literals. // Fill in the literals.
bool is_simple = true;
for (int i = 0; i < values.length(); i++) { for (int i = 0; i < values.length(); i++) {
Handle<Object> boilerplate_value = GetBoilerplateValue(values.at(i)); Literal* literal = values.at(i)->AsLiteral();
if (boilerplate_value->IsUndefined()) { if (literal == NULL) {
literals->set_the_hole(i); literals->set_the_hole(i);
is_simple = false;
} else { } else {
literals->set(i, *boilerplate_value); literals->set(i, *literal->handle());
} }
} }
return NEW(ArrayLiteral(literals, values.elements(), return NEW(ArrayLiteral(literals, values.elements()));
literal_index, is_simple));
} }
...@@ -3089,48 +3083,10 @@ bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) { ...@@ -3089,48 +3083,10 @@ bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
} }
bool CompileTimeValue::IsCompileTimeValue(Expression* expression) { Literal* Parser::GetBoilerplateValue(ObjectLiteral::Property* property) {
MaterializedLiteral* lit = expression->AsMaterializedLiteral(); if (property->kind() == ObjectLiteral::Property::CONSTANT)
return lit != NULL && lit->is_simple(); return property->value()->AsLiteral();
} return GetLiteralUndefined();
Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
ASSERT(IsCompileTimeValue(expression));
Handle<FixedArray> result = Factory::NewFixedArray(2, TENURED);
ObjectLiteral* object_literal = expression->AsObjectLiteral();
if (object_literal != NULL) {
ASSERT(object_literal->is_simple());
result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL));
result->set(kElementsSlot, *object_literal->constant_properties());
} else {
ArrayLiteral* array_literal = expression->AsArrayLiteral();
ASSERT(array_literal != NULL && array_literal->is_simple());
result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
result->set(kElementsSlot, *array_literal->literals());
}
return result;
}
CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
Smi* type_value = Smi::cast(value->get(kTypeSlot));
return static_cast<Type>(type_value->value());
}
Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
}
Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
if (expression->AsLiteral() != NULL) {
return expression->AsLiteral()->handle();
}
if (CompileTimeValue::IsCompileTimeValue(expression)) {
return CompileTimeValue::GetValue(expression);
}
return Factory::undefined_value();
} }
...@@ -3225,30 +3181,24 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { ...@@ -3225,30 +3181,24 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Handle<FixedArray> constant_properties = Handle<FixedArray> constant_properties =
Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED); Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
int position = 0; int position = 0;
bool is_simple = true;
for (int i = 0; i < properties.length(); i++) { for (int i = 0; i < properties.length(); i++) {
ObjectLiteral::Property* property = properties.at(i); ObjectLiteral::Property* property = properties.at(i);
if (!IsBoilerplateProperty(property)) { if (!IsBoilerplateProperty(property)) continue;
is_simple = false;
continue;
}
// Add CONSTANT and COMPUTED properties to boilerplate. Use undefined // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
// value for COMPUTED properties, the real value is filled in at // value for COMPUTED properties, the real value is filled in at
// runtime. The enumeration order is maintained. // runtime. The enumeration order is maintained.
Handle<Object> key = property->key()->handle(); Handle<Object> key = property->key()->handle();
Handle<Object> value = GetBoilerplateValue(property->value()); Literal* literal = GetBoilerplateValue(property);
is_simple = is_simple && !value->IsUndefined();
// Add name, value pair to the fixed array. // Add name, value pair to the fixed array.
constant_properties->set(position++, *key); constant_properties->set(position++, *key);
constant_properties->set(position++, *value); constant_properties->set(position++, *literal->handle());
} }
return new ObjectLiteral(constant_properties, return new ObjectLiteral(constant_properties,
properties.elements(), properties.elements(),
literal_index, literal_index);
is_simple);
} }
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#define V8_PARSER_H_ #define V8_PARSER_H_
#include "scanner.h" #include "scanner.h"
#include "allocation.h"
namespace v8 { namespace internal { namespace v8 { namespace internal {
...@@ -166,35 +165,6 @@ FunctionLiteral* MakeLazyAST(Handle<Script> script, ...@@ -166,35 +165,6 @@ FunctionLiteral* MakeLazyAST(Handle<Script> script,
int end_position, int end_position,
bool is_expression); bool is_expression);
// Support for handling complex values (array and object literals) that
// can be fully handled at compile time.
class CompileTimeValue: public AllStatic {
public:
enum Type {
OBJECT_LITERAL,
ARRAY_LITERAL
};
static bool IsCompileTimeValue(Expression* expression);
// Get the value as a compile time value.
static Handle<FixedArray> GetValue(Expression* expression);
// Get the type of a compile time value returned by GetValue().
static Type GetType(Handle<FixedArray> value);
// Get the elements array of a compile time value returned by GetValue().
static Handle<FixedArray> GetElements(Handle<FixedArray> value);
private:
static const int kTypeSlot = 0;
static const int kElementsSlot = 1;
DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
};
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_PARSER_H_ #endif // V8_PARSER_H_
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
#include "scopeinfo.h" #include "scopeinfo.h"
#include "v8threads.h" #include "v8threads.h"
#include "smart-pointer.h" #include "smart-pointer.h"
#include "parser.h"
namespace v8 { namespace internal { namespace v8 { namespace internal {
...@@ -70,13 +69,6 @@ namespace v8 { namespace internal { ...@@ -70,13 +69,6 @@ namespace v8 { namespace internal {
RUNTIME_ASSERT(obj->IsBoolean()); \ RUNTIME_ASSERT(obj->IsBoolean()); \
bool name = (obj)->IsTrue(); bool name = (obj)->IsTrue();
// Cast the given object to an int and store it in a variable with
// the given name. If the object is not a Smi call IllegalOperation
// and return.
#define CONVERT_INT_CHECKED(name, obj) \
RUNTIME_ASSERT(obj->IsSmi()); \
int name = Smi::cast(obj)->value();
// Cast the given object to a double and store it in a variable with // Cast the given object to a double and store it in a variable with
// the given name. If the object is not a number (as opposed to // the given name. If the object is not a number (as opposed to
// the number not-a-number) call IllegalOperation and return. // the number not-a-number) call IllegalOperation and return.
...@@ -100,7 +92,7 @@ static Object* IllegalOperation() { ...@@ -100,7 +92,7 @@ static Object* IllegalOperation() {
} }
static Object* Runtime_CloneLiteralBoilerplate(Arguments args) { static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
CONVERT_CHECKED(JSObject, boilerplate, args[0]); CONVERT_CHECKED(JSObject, boilerplate, args[0]);
return Heap::CopyJSObject(boilerplate); return Heap::CopyJSObject(boilerplate);
} }
...@@ -139,14 +131,14 @@ static Handle<Map> ComputeObjectLiteralMap( ...@@ -139,14 +131,14 @@ static Handle<Map> ComputeObjectLiteralMap(
} }
static Handle<Object> CreateLiteralBoilerplate( static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
Handle<FixedArray> literals, HandleScope scope;
Handle<FixedArray> constant_properties); ASSERT(args.length() == 3);
// Copy the arguments.
Handle<FixedArray> literals = args.at<FixedArray>(0);
int literals_index = Smi::cast(args[1])->value();
Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
static Handle<Object> CreateObjectLiteralBoilerplate(
Handle<FixedArray> literals,
Handle<FixedArray> constant_properties) {
// Get the global context from the literals array. This is the // Get the global context from the literals array. This is the
// context in which the function was created and we use the object // context in which the function was created and we use the object
// function from this context to create the object literal. We do // function from this context to create the object literal. We do
...@@ -169,13 +161,6 @@ static Handle<Object> CreateObjectLiteralBoilerplate( ...@@ -169,13 +161,6 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
for (int index = 0; index < length; index +=2) { for (int index = 0; index < length; index +=2) {
Handle<Object> key(constant_properties->get(index+0)); Handle<Object> key(constant_properties->get(index+0));
Handle<Object> value(constant_properties->get(index+1)); Handle<Object> value(constant_properties->get(index+1));
if (value->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object literal.
Handle<FixedArray> array = Handle<FixedArray>::cast(value);
value = CreateLiteralBoilerplate(literals, array);
if (value.is_null()) return value;
}
Handle<Object> result; Handle<Object> result;
uint32_t element_index = 0; uint32_t element_index = 0;
if (key->IsSymbol()) { if (key->IsSymbol()) {
...@@ -200,96 +185,39 @@ static Handle<Object> CreateObjectLiteralBoilerplate( ...@@ -200,96 +185,39 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
// exception, the exception is converted to an empty handle in // exception, the exception is converted to an empty handle in
// the handle based operations. In that case, we need to // the handle based operations. In that case, we need to
// convert back to an exception. // convert back to an exception.
if (result.is_null()) return result; if (result.is_null()) return Failure::Exception();
} }
} }
return boilerplate;
}
static Handle<Object> CreateArrayLiteralBoilerplate(
Handle<FixedArray> literals,
Handle<FixedArray> elements) {
// Create the JSArray.
Handle<JSFunction> constructor(
JSFunction::GlobalContextFromLiterals(*literals)->array_function());
Handle<Object> object = Factory::NewJSObject(constructor);
Handle<Object> copied_elements = Factory::CopyFixedArray(elements);
Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
for (int i = 0; i < content->length(); i++) {
if (content->get(i)->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object literal.
Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
Handle<Object> result = CreateLiteralBoilerplate(literals, fa);
if (result.is_null()) return result;
content->set(i, *result);
}
}
// Set the elements.
Handle<JSArray>::cast(object)->SetContent(*content);
return object;
}
static Handle<Object> CreateLiteralBoilerplate(
Handle<FixedArray> literals,
Handle<FixedArray> array) {
Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
switch (CompileTimeValue::GetType(array)) {
case CompileTimeValue::OBJECT_LITERAL:
return CreateObjectLiteralBoilerplate(literals, elements);
case CompileTimeValue::ARRAY_LITERAL:
return CreateArrayLiteralBoilerplate(literals, elements);
default:
UNREACHABLE();
return Handle<Object>::null();
}
}
static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
// Copy the arguments.
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_INT_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Handle<Object> result =
CreateObjectLiteralBoilerplate(literals, constant_properties);
if (result.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate. // Update the functions literal and return the boilerplate.
literals->set(literals_index, *result); literals->set(literals_index, *boilerplate);
return *result; return *boilerplate;
} }
static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { static Object* Runtime_CreateArrayLiteral(Arguments args) {
// Takes a FixedArray of elements containing the literal elements of // Takes a FixedArray of elements containing the literal elements of
// the array literal and produces JSArray with those elements. // the array literal and produces JSArray with those elements.
// Additionally takes the literals array of the surrounding function // Additionally takes the literals array of the surrounding function
// which contains the context from which to get the Array function // which contains the context from which to get the Array function
// to use for creating the array literal. // to use for creating the array literal.
HandleScope scope; ASSERT(args.length() == 2);
ASSERT(args.length() == 3); CONVERT_CHECKED(FixedArray, elements, args[0]);
CONVERT_ARG_CHECKED(FixedArray, literals, 0); CONVERT_CHECKED(FixedArray, literals, args[1]);
CONVERT_INT_CHECKED(literals_index, args[1]); JSFunction* constructor =
CONVERT_ARG_CHECKED(FixedArray, elements, 2); JSFunction::GlobalContextFromLiterals(literals)->array_function();
// Create the JSArray.
Object* object = Heap::AllocateJSObject(constructor);
if (object->IsFailure()) return object;
Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); // Copy the elements.
if (object.is_null()) return Failure::Exception(); Object* content = elements->Copy();
if (content->IsFailure()) return content;
// Update the functions literal and return the boilerplate. // Set the elements.
literals->set(literals_index, *object); JSArray::cast(object)->SetContent(FixedArray::cast(content));
return *object; return object;
} }
......
...@@ -251,9 +251,9 @@ namespace v8 { namespace internal { ...@@ -251,9 +251,9 @@ namespace v8 { namespace internal {
\ \
/* Literals */ \ /* Literals */ \
F(MaterializeRegExpLiteral, 4)\ F(MaterializeRegExpLiteral, 4)\
F(CreateArrayLiteralBoilerplate, 3) \ F(CreateArrayLiteral, 2) \
F(CreateObjectLiteralBoilerplate, 3) \ F(CreateObjectLiteralBoilerplate, 3) \
F(CloneLiteralBoilerplate, 1) \ F(CloneObjectLiteralBoilerplate, 1) \
\ \
/* Catch context extension objects */ \ /* Catch context extension objects */ \
F(CreateCatchExtensionObject, 2) \ F(CreateCatchExtensionObject, 2) \
...@@ -326,6 +326,7 @@ class Runtime : public AllStatic { ...@@ -326,6 +326,7 @@ class Runtime : public AllStatic {
kNofFunctions kNofFunctions
#undef F #undef F
}; };
static Object* CreateArrayLiteral(Arguments args);
// Runtime function descriptor. // Runtime function descriptor.
struct Function { struct Function {
......
...@@ -121,8 +121,7 @@ var knownProblems = { ...@@ -121,8 +121,7 @@ var knownProblems = {
"PushContext": true, "PushContext": true,
"LazyCompile": true, "LazyCompile": true,
"CreateObjectLiteralBoilerplate": true, "CreateObjectLiteralBoilerplate": true,
"CloneLiteralBoilerplate": true, "CloneObjectLiteralBoilerplate": true,
"CreateArrayLiteralBoilerplate": true,
"IS_VAR": true, "IS_VAR": true,
"ResolvePossiblyDirectEval": true, "ResolvePossiblyDirectEval": true,
"Log": true "Log": true
......
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function makeArrayInObject() {
return { foo: [] };
}
var a = makeArrayInObject();
a.foo.push(5);
var b = makeArrayInObject();
assertEquals(0, b.foo.length, "Array in object");
function makeObjectInObject() {
return { foo: {} };
}
a = makeObjectInObject();
a.foo.bar = 1;
b = makeObjectInObject();
assertEquals('undefined', typeof(b.foo.bar), "Object in object");
function makeObjectInArray() {
return [ {} ];
}
a = makeObjectInArray();
a[0].bar = 1;
b = makeObjectInArray();
assertEquals('undefined', typeof(b[0].bar), "Object in object");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment