Author: olehougaard Date: Tue Mar 10 01:59:00 2009 New Revision: 1469 Modified: branches/bleeding_edge/src/ast.cc branches/bleeding_edge/src/ast.h branches/bleeding_edge/src/codegen-arm.cc branches/bleeding_edge/src/codegen-ia32.cc branches/bleeding_edge/src/heap.h branches/bleeding_edge/src/parser.cc branches/bleeding_edge/src/parser.h branches/bleeding_edge/src/runtime.cc branches/bleeding_edge/src/runtime.h branches/bleeding_edge/test/mjsunit/fuzz-natives.js
Log: Optimizing generation of nested literals for both object and array literals. Review URL: http://codereview.chromium.org/40295 Modified: branches/bleeding_edge/src/ast.cc ============================================================================== --- branches/bleeding_edge/src/ast.cc (original) +++ branches/bleeding_edge/src/ast.cc Tue Mar 10 01:59:00 2009 @@ -135,10 +135,12 @@ Object* k = *key->handle(); if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) { kind_ = PROTOTYPE; - } else if (value_->AsObjectLiteral() != NULL) { - kind_ = OBJECT_LITERAL; + } else if (value_->AsMaterializedLiteral() != NULL) { + kind_ = MATERIALIZED_LITERAL; + } else if (value_->AsLiteral() != NULL) { + kind_ = CONSTANT; } else { - kind_ = value_->AsLiteral() == NULL ? COMPUTED : CONSTANT; + kind_ = COMPUTED; } } Modified: branches/bleeding_edge/src/ast.h ============================================================================== --- branches/bleeding_edge/src/ast.h (original) +++ branches/bleeding_edge/src/ast.h Tue Mar 10 01:59:00 2009 @@ -95,6 +95,7 @@ // Forward declarations class TargetCollector; +class MaterializedLiteral; #define DEF_FORWARD_DECLARATION(type) class type; NODE_LIST(DEF_FORWARD_DECLARATION) @@ -129,7 +130,9 @@ virtual BinaryOperation* AsBinaryOperation() { return NULL; } virtual Assignment* AsAssignment() { 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; } int statement_pos() const { return statement_pos_; } @@ -633,11 +636,20 @@ // Base class for literals that needs space in the corresponding JSFunction. class MaterializedLiteral: public Expression { public: - explicit MaterializedLiteral(int literal_index) - : literal_index_(literal_index) {} + explicit MaterializedLiteral(int literal_index, bool is_simple) + : literal_index_(literal_index), is_simple_(is_simple) {} + + virtual MaterializedLiteral* AsMaterializedLiteral() { return this; } + 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: int literal_index_; + bool is_simple_; }; @@ -652,11 +664,11 @@ public: enum Kind { - CONSTANT, // Property with constant value (at compile time). - COMPUTED, // Property with computed value (at execution time). - OBJECT_LITERAL, // Property value is an object literal. - GETTER, SETTER, // Property is an accessor function. - PROTOTYPE // Property is __proto__. + CONSTANT, // Property with constant value (compile time). + COMPUTED, // Property with computed value (execution time). + MATERIALIZED_LITERAL, // Property value is a materialized literal. + GETTER, SETTER, // Property is an accessor function. + PROTOTYPE // Property is __proto__. }; Property(Literal* key, Expression* value); @@ -676,11 +688,9 @@ ZoneList<Property*>* properties, int literal_index, bool is_simple) - : MaterializedLiteral(literal_index), + : MaterializedLiteral(literal_index, is_simple), constant_properties_(constant_properties), - properties_(properties), - is_simple_(is_simple) { - } + properties_(properties) {} virtual ObjectLiteral* AsObjectLiteral() { return this; } virtual void Accept(AstVisitor* v); @@ -690,14 +700,9 @@ } ZoneList<Property*>* properties() const { return properties_; } - // An object literal is simple if the values consist of only - // constants and simple object literals. - bool is_simple() const { return is_simple_; } - private: Handle<FixedArray> constant_properties_; ZoneList<Property*>* properties_; - bool is_simple_; }; @@ -707,7 +712,7 @@ RegExpLiteral(Handle<String> pattern, Handle<String> flags, int literal_index) - : MaterializedLiteral(literal_index), + : MaterializedLiteral(literal_index, false), pattern_(pattern), flags_(flags) {} @@ -723,14 +728,18 @@ // An array literal has a literals object that is used // for minimizing the work when constructing it at runtime. -class ArrayLiteral: public Expression { +class ArrayLiteral: public MaterializedLiteral { public: ArrayLiteral(Handle<FixedArray> literals, - ZoneList<Expression*>* values) - : literals_(literals), values_(values) { - } + ZoneList<Expression*>* values, + int literal_index, + bool is_simple) + : MaterializedLiteral(literal_index, is_simple), + literals_(literals), + values_(values) {} virtual void Accept(AstVisitor* v); + virtual ArrayLiteral* AsArrayLiteral() { return this; } Handle<FixedArray> literals() const { return literals_; } ZoneList<Expression*>* values() const { return values_; } Modified: branches/bleeding_edge/src/codegen-arm.cc ============================================================================== --- branches/bleeding_edge/src/codegen-arm.cc (original) +++ branches/bleeding_edge/src/codegen-arm.cc Tue Mar 10 01:59:00 2009 @@ -2619,7 +2619,7 @@ // This deferred code stub will be used for creating the boilerplate -// by calling Runtime_CreateObjectLiteral. +// by calling Runtime_CreateObjectLiteralBoilerplate. // Each created boilerplate is stored in the JSFunction and they are // therefore context dependent. class DeferredObjectLiteral: public DeferredCode { @@ -2693,7 +2693,7 @@ frame_->EmitPush(r2); // Clone the boilerplate object. - frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); + frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); frame_->EmitPush(r0); // save the result // r0: cloned object literal @@ -2702,9 +2702,11 @@ Literal* key = property->key(); Expression* value = property->value(); switch (property->kind()) { - case ObjectLiteral::Property::CONSTANT: break; - case ObjectLiteral::Property::OBJECT_LITERAL: - if (property->value()->AsObjectLiteral()->is_simple()) break; + case ObjectLiteral::Property::CONSTANT: + 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::PROTOTYPE: { frame_->EmitPush(r0); // dup the result @@ -2741,6 +2743,49 @@ } +// 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) { #ifdef DEBUG int original_height = frame_->height(); @@ -2748,17 +2793,34 @@ VirtualFrame::SpilledScope spilled_scope(this); Comment cmnt(masm_, "[ ArrayLiteral"); - // Call runtime to create the array literal. - __ mov(r0, Operand(node->literals())); - frame_->EmitPush(r0); - // Load the function of this frame. - __ ldr(r0, frame_->Function()); - __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); - frame_->EmitPush(r0); - frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); + DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node); + + // Retrieve the literal array and check the allocated entry. + + // Load the function of this activation. + __ ldr(r1, frame_->Function()); + + // Load the literals array of the function. + __ 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); - // Push the resulting array literal on the stack. - frame_->EmitPush(r0); + // Clone the boilerplate object. + frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); + frame_->EmitPush(r0); // save the result + // r0: cloned object literal // Generate code to set the elements in the array that are not // literals. Modified: branches/bleeding_edge/src/codegen-ia32.cc ============================================================================== --- branches/bleeding_edge/src/codegen-ia32.cc (original) +++ branches/bleeding_edge/src/codegen-ia32.cc Tue Mar 10 01:59:00 2009 @@ -32,6 +32,7 @@ #include "debug.h" #include "scopes.h" #include "runtime.h" +#include "parser.h" namespace v8 { namespace internal { @@ -3488,7 +3489,7 @@ frame_->Push(&boilerplate); // Clone the boilerplate object. Result clone = - frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); + frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); // Push the newly cloned literal object as the result. frame_->Push(&clone); @@ -3497,8 +3498,9 @@ switch (property->kind()) { case ObjectLiteral::Property::CONSTANT: break; - case ObjectLiteral::Property::OBJECT_LITERAL: - if (property->value()->AsObjectLiteral()->is_simple()) 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)); @@ -3556,59 +3558,123 @@ } +// 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. + 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 // 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); - - // Get the property value off the stack. - Result prop_value = frame_->Pop(); - prop_value.ToRegister(); + 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; + + // The property must be set by generated code. + Load(value); + + // Get the property value off the stack. + Result prop_value = frame_->Pop(); + prop_value.ToRegister(); - // 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)); - - // 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()); - } + // 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)); + + // 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()); } } Modified: branches/bleeding_edge/src/heap.h ============================================================================== --- branches/bleeding_edge/src/heap.h (original) +++ branches/bleeding_edge/src/heap.h Tue Mar 10 01:59:00 2009 @@ -166,8 +166,6 @@ V(char_at_symbol, "CharAt") \ V(undefined_symbol, "undefined") \ V(value_of_symbol, "valueOf") \ - V(CreateObjectLiteralBoilerplate_symbol, "CreateObjectLiteralBoilerplate") \ - V(CreateArrayLiteral_symbol, "CreateArrayLiteral") \ V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \ V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \ V(stack_overflow_symbol, "kStackOverflowBoilerplate") \ Modified: branches/bleeding_edge/src/parser.cc ============================================================================== --- branches/bleeding_edge/src/parser.cc (original) +++ branches/bleeding_edge/src/parser.cc Tue Mar 10 01:59:00 2009 @@ -158,13 +158,12 @@ // Decide if a property should be the object boilerplate. bool IsBoilerplateProperty(ObjectLiteral::Property* property); - // If the property is CONSTANT type, return the literal value; - // if the property is OBJECT_LITERAL and the object literal is - // simple return a fixed array containing the keys and values of the - // object literal. + // If the expression is a literal, return the literal value; + // if the expression is a materialized literal and is simple return a + // compile time value as encoded by CompileTimeValue::GetValue(). // Otherwise, return undefined literal as the placeholder // in the object literal boilerplate. - Handle<Object> GetBoilerplateValue(ObjectLiteral::Property* property); + Handle<Object> GetBoilerplateValue(Expression* expression); enum FunctionLiteralType { EXPRESSION, @@ -3059,6 +3058,7 @@ // Update the scope information before the pre-parsing bailout. temp_scope_->set_contains_array_literal(); + int literal_index = temp_scope_->NextMaterializedLiteralIndex(); if (is_pre_parsing_) return NULL; @@ -3067,16 +3067,19 @@ Factory::NewFixedArray(values.length(), TENURED); // Fill in the literals. + bool is_simple = true; for (int i = 0; i < values.length(); i++) { - Literal* literal = values.at(i)->AsLiteral(); - if (literal == NULL) { + Handle<Object> boilerplate_value = GetBoilerplateValue(values.at(i)); + if (boilerplate_value->IsUndefined()) { literals->set_the_hole(i); + is_simple = false; } else { - literals->set(i, *literal->handle()); + literals->set(i, *boilerplate_value); } } - return NEW(ArrayLiteral(literals, values.elements())); + return NEW(ArrayLiteral(literals, values.elements(), + literal_index, is_simple)); } @@ -3086,14 +3089,46 @@ } -Handle<Object> Parser::GetBoilerplateValue(ObjectLiteral::Property* property) { - if (property->kind() == ObjectLiteral::Property::CONSTANT) - return property->value()->AsLiteral()->handle(); - if (property->kind() == ObjectLiteral::Property::OBJECT_LITERAL) { - ObjectLiteral* object_literal = property->value()->AsObjectLiteral(); - if (object_literal->is_simple()) { - return object_literal->constant_properties(); - } +bool CompileTimeValue::IsCompileTimeValue(Expression* expression) { + MaterializedLiteral* lit = expression->AsMaterializedLiteral(); + return lit != NULL && lit->is_simple(); +} + +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(); } @@ -3202,7 +3237,7 @@ // value for COMPUTED properties, the real value is filled in at // runtime. The enumeration order is maintained. Handle<Object> key = property->key()->handle(); - Handle<Object> value = GetBoilerplateValue(property); + Handle<Object> value = GetBoilerplateValue(property->value()); is_simple = is_simple && !value->IsUndefined(); // Add name, value pair to the fixed array. Modified: branches/bleeding_edge/src/parser.h ============================================================================== --- branches/bleeding_edge/src/parser.h (original) +++ branches/bleeding_edge/src/parser.h Tue Mar 10 01:59:00 2009 @@ -29,6 +29,7 @@ #define V8_PARSER_H_ #include "scanner.h" +#include "allocation.h" namespace v8 { namespace internal { @@ -164,6 +165,35 @@ int start_position, int end_position, 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 Modified: branches/bleeding_edge/src/runtime.cc ============================================================================== --- branches/bleeding_edge/src/runtime.cc (original) +++ branches/bleeding_edge/src/runtime.cc Tue Mar 10 01:59:00 2009 @@ -43,6 +43,7 @@ #include "scopeinfo.h" #include "v8threads.h" #include "smart-pointer.h" +#include "parser.h" namespace v8 { namespace internal { @@ -69,6 +70,13 @@ RUNTIME_ASSERT(obj->IsBoolean()); \ 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 // the given name. If the object is not a number (as opposed to // the number not-a-number) call IllegalOperation and return. @@ -92,7 +100,7 @@ } -static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) { +static Object* Runtime_CloneLiteralBoilerplate(Arguments args) { CONVERT_CHECKED(JSObject, boilerplate, args[0]); return Heap::CopyJSObject(boilerplate); } @@ -131,6 +139,11 @@ } +static Handle<Object> CreateLiteralBoilerplate( + Handle<FixedArray> literals, + Handle<FixedArray> constant_properties); + + static Handle<Object> CreateObjectLiteralBoilerplate( Handle<FixedArray> literals, Handle<FixedArray> constant_properties) { @@ -160,7 +173,8 @@ // The value contains the constant_properties of a // simple object literal. Handle<FixedArray> array = Handle<FixedArray>::cast(value); - value = CreateObjectLiteralBoilerplate(literals, array); + value = CreateLiteralBoilerplate(literals, array); + if (value.is_null()) return value; } Handle<Object> result; uint32_t element_index = 0; @@ -194,13 +208,57 @@ } +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. - Handle<FixedArray> literals = args.at<FixedArray>(0); - int literals_index = Smi::cast(args[1])->value(); - Handle<FixedArray> constant_properties = args.at<FixedArray>(2); + 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); @@ -214,28 +272,24 @@ } -static Object* Runtime_CreateArrayLiteral(Arguments args) { +static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { // Takes a FixedArray of elements containing the literal elements of // the array literal and produces JSArray with those elements. // Additionally takes the literals array of the surrounding function // which contains the context from which to get the Array function // to use for creating the array literal. - ASSERT(args.length() == 2); - CONVERT_CHECKED(FixedArray, elements, args[0]); - CONVERT_CHECKED(FixedArray, literals, args[1]); - JSFunction* constructor = - JSFunction::GlobalContextFromLiterals(literals)->array_function(); - // Create the JSArray. - Object* object = Heap::AllocateJSObject(constructor); - if (object->IsFailure()) return object; + HandleScope scope; + ASSERT(args.length() == 3); + CONVERT_ARG_CHECKED(FixedArray, literals, 0); + CONVERT_INT_CHECKED(literals_index, args[1]); + CONVERT_ARG_CHECKED(FixedArray, elements, 2); - // Copy the elements. - Object* content = elements->Copy(); - if (content->IsFailure()) return content; + Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); + if (object.is_null()) return Failure::Exception(); - // Set the elements. - JSArray::cast(object)->SetContent(FixedArray::cast(content)); - return object; + // Update the functions literal and return the boilerplate. + literals->set(literals_index, *object); + return *object; } Modified: branches/bleeding_edge/src/runtime.h ============================================================================== --- branches/bleeding_edge/src/runtime.h (original) +++ branches/bleeding_edge/src/runtime.h Tue Mar 10 01:59:00 2009 @@ -250,9 +250,9 @@ \ /* Literals */ \ F(MaterializeRegExpLiteral, 4)\ - F(CreateArrayLiteral, 2) \ + F(CreateArrayLiteralBoilerplate, 3) \ F(CreateObjectLiteralBoilerplate, 3) \ - F(CloneObjectLiteralBoilerplate, 1) \ + F(CloneLiteralBoilerplate, 1) \ \ /* Catch context extension objects */ \ F(CreateCatchExtensionObject, 2) \ @@ -325,7 +325,6 @@ kNofFunctions #undef F }; - static Object* CreateArrayLiteral(Arguments args); // Runtime function descriptor. struct Function { Modified: branches/bleeding_edge/test/mjsunit/fuzz-natives.js ============================================================================== --- branches/bleeding_edge/test/mjsunit/fuzz-natives.js (original) +++ branches/bleeding_edge/test/mjsunit/fuzz-natives.js Tue Mar 10 01:59:00 2009 @@ -121,7 +121,8 @@ "PushContext": true, "LazyCompile": true, "CreateObjectLiteralBoilerplate": true, - "CloneObjectLiteralBoilerplate": true, + "CloneLiteralBoilerplate": true, + "CreateArrayLiteralBoilerplate": true, "IS_VAR": true, "ResolvePossiblyDirectEval": true, "Log": true --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list v8-dev@googlegroups.com http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---