Revision: 3110
Author: [email protected]
Date: Thu Oct 22 03:07:45 2009
Log: Added support for array literals to the toplevel compiler.  They are
currently compiled the same as with the optimizing compiler: they are
cloned from a boilerplate object and the boilerplate objects are
lazily constructed.

Also changed argument pushing on ARM to use stm (store multiple),
which required changing the order of arguments to the runtime
functions DeclareGlobals and NewClosure.  They were only used from
generated code.

Finally, changed the toplevel code generator so that stack pops to
discard a temporary became addition to the stack pointer on ia32 and
x64.

Review URL: http://codereview.chromium.org/303021
http://code.google.com/p/v8/source/detail?r=3110

Modified:
  /branches/bleeding_edge/src/arm/codegen-arm.cc
  /branches/bleeding_edge/src/arm/fast-codegen-arm.cc
  /branches/bleeding_edge/src/compiler.cc
  /branches/bleeding_edge/src/fast-codegen.cc
  /branches/bleeding_edge/src/ia32/codegen-ia32.cc
  /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc
  /branches/bleeding_edge/src/runtime.cc
  /branches/bleeding_edge/src/x64/codegen-x64.cc
  /branches/bleeding_edge/src/x64/fast-codegen-x64.cc
  /branches/bleeding_edge/test/mjsunit/compiler/literals.js

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Mon Oct 12 06:14:06 2009
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Oct 22 03:07:45 2009
@@ -1172,9 +1172,9 @@

  void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
    VirtualFrame::SpilledScope spilled_scope;
+  frame_->EmitPush(cp);
    __ mov(r0, Operand(pairs));
    frame_->EmitPush(r0);
-  frame_->EmitPush(cp);
    __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
    frame_->EmitPush(r0);
    frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
@@ -2255,12 +2255,10 @@
    VirtualFrame::SpilledScope spilled_scope;
    ASSERT(boilerplate->IsBoilerplate());

-  // Push the boilerplate on the stack.
-  __ mov(r0, Operand(boilerplate));
-  frame_->EmitPush(r0);
-
    // Create a new closure.
    frame_->EmitPush(cp);
+  __ mov(r0, Operand(boilerplate));
+  frame_->EmitPush(r0);
    frame_->CallRuntime(Runtime::kNewClosure, 2);
    frame_->EmitPush(r0);
  }
=======================================
--- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Thu Oct 22 02:29:03  
2009
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Thu Oct 22 03:07:45  
2009
@@ -29,6 +29,7 @@

  #include "codegen-inl.h"
  #include "fast-codegen.h"
+#include "parser.h"

  namespace v8 {
  namespace internal {
@@ -110,11 +111,10 @@

  void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
    // Call the runtime to declare the globals.
-  __ mov(r0, Operand(pairs));
-  __ push(r0);
-  __ push(cp);  // The context is the second argument.
+  // The context is the first argument.
+  __ mov(r1, Operand(pairs));
    __ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0)));
-  __ push(r0);
+  __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit());
    __ CallRuntime(Runtime::kDeclareGlobals, 3);
    // Return value is ignored.
  }
@@ -153,7 +153,7 @@
    __ RecordJSReturn();
    __ mov(sp, fp);
    __ ldm(ia_w, sp, fp.bit() | lr.bit());
-    int num_parameters = function_->scope()->num_parameters();
+  int num_parameters = function_->scope()->num_parameters();
    __ add(sp, sp, Operand((num_parameters + 1) * kPointerSize));
    __ Jump(lr);
  }
@@ -170,8 +170,7 @@

    // Create a new closure.
    __ mov(r0, Operand(boilerplate));
-  __ push(r0);
-  __ push(cp);
+  __ stm(db_w, sp, cp.bit() | r0.bit());
    __ CallRuntime(Runtime::kNewClosure, 2);

    if (expr->location().is_temporary()) {
@@ -214,6 +213,7 @@
      }
    }
  }
+

  void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
    Comment cmnt(masm_, "[ RegExp Literal");
@@ -244,6 +244,80 @@
      ASSERT(expr->location().is_nowhere());
    }
  }
+
+
+void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+  Label make_clone;
+
+  // Fetch the function's literals array.
+  __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
+  // Check if the literal's boilerplate has been instantiated.
+  int offset =
+      FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
+  __ ldr(r0, FieldMemOperand(r3, offset));
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(r0, ip);
+  __ b(&make_clone, ne);
+
+  // Instantiate the boilerplate.
+  __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
+  __ mov(r1, Operand(expr->literals()));
+  __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
+  __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
+
+  __ bind(&make_clone);
+  // Clone the boilerplate.
+  __ push(r0);
+  if (expr->depth() > 1) {
+    __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
+  } else {
+    __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
+  }
+
+  bool result_saved = false;  // Is the result saved to the stack?
+
+  // Emit code to evaluate all the non-constant subexpressions and to store
+  // them into the newly cloned array.
+  ZoneList<Expression*>* subexprs = expr->values();
+  for (int i = 0, len = subexprs->length(); i < len; i++) {
+    Expression* subexpr = subexprs->at(i);
+    // If the subexpression is a literal or a simple materialized literal  
it
+    // is already set in the cloned array.
+    if (subexpr->AsLiteral() != NULL ||
+        CompileTimeValue::IsCompileTimeValue(subexpr)) {
+      continue;
+    }
+
+    if (!result_saved) {
+      __ push(r0);
+      result_saved = true;
+    }
+    Visit(subexpr);
+    ASSERT(subexpr->location().is_temporary());
+
+    // Store the subexpression value in the array's elements.
+    __ pop(r0);  // Subexpression value.
+    __ ldr(r1, MemOperand(sp));  // Copy of array literal.
+    __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
+    int offset = FixedArray::kHeaderSize + (i * kPointerSize);
+    __ str(r0, FieldMemOperand(r1, offset));
+
+    // Update the write barrier for the array store with r0 as the scratch
+    // register.
+    __ mov(r2, Operand(offset));
+    __ RecordWrite(r1, r2, r0);
+  }
+
+  Location destination = expr->location();
+  if (destination.is_nowhere() && result_saved) {
+    __ pop();
+  } else if (destination.is_temporary() && !result_saved) {
+    __ push(r0);
+  }
+}
+

  void FastCodeGenerator::VisitAssignment(Assignment* expr) {
    Comment cmnt(masm_, "[ Assignment");
@@ -323,11 +397,10 @@
    ASSERT(var != NULL && !var->is_this() && var->is_global());
    ASSERT(!var->is_possibly_eval());

-  __ mov(r0, Operand(var->name()));
-  __ push(r0);
-  // Push global object (receiver)
+  __ mov(r1, Operand(var->name()));
+  // Push global object as receiver.
    __ ldr(r0, CodeGenerator::GlobalObject());
-  __ push(r0);
+  __ stm(db_w, sp, r1.bit() | r0.bit());
    int arg_count = args->length();
    for (int i = 0; i < arg_count; i++) {
      Visit(args->at(i));
=======================================
--- /branches/bleeding_edge/src/compiler.cc     Thu Oct 22 02:29:03 2009
+++ /branches/bleeding_edge/src/compiler.cc     Thu Oct 22 03:07:45 2009
@@ -644,7 +644,14 @@


  void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
-  BAILOUT("ArrayLiteral");
+  ZoneList<Expression*>* subexprs = expr->values();
+  for (int i = 0, len = subexprs->length(); i < len; i++) {
+    Expression* subexpr = subexprs->at(i);
+    if (subexpr->AsLiteral() != NULL) continue;
+    if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+    Visit(subexpr);
+    CHECK_BAILOUT;
+  }
  }


=======================================
--- /branches/bleeding_edge/src/fast-codegen.cc Thu Oct 22 02:29:03 2009
+++ /branches/bleeding_edge/src/fast-codegen.cc Thu Oct 22 03:07:45 2009
@@ -287,11 +287,6 @@
  void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
    UNREACHABLE();
  }
-
-
-void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
-  UNREACHABLE();
-}


  void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject*  
expr) {
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Wed Oct 21 02:24:25  
2009
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Thu Oct 22 03:07:45  
2009
@@ -2275,8 +2275,8 @@
    // allow us to push the arguments directly into place.
    frame_->SyncRange(0, frame_->element_count() - 1);

+  frame_->EmitPush(esi);  // The context is the first argument.
    frame_->EmitPush(Immediate(pairs));
-  frame_->EmitPush(esi);  // The context is the second argument.
    frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
    Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
    // Return value is ignored.
@@ -3576,11 +3576,9 @@
    ASSERT(boilerplate->IsBoilerplate());
    frame_->SyncRange(0, frame_->element_count() - 1);

-  // Push the boilerplate on the stack.
-  frame_->EmitPush(Immediate(boilerplate));
-
    // Create a new closure.
    frame_->EmitPush(esi);
+  frame_->EmitPush(Immediate(boilerplate));
    Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
    frame_->Push(&result);
  }
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc       Thu Oct 22  
02:29:03 2009
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc       Thu Oct 22  
03:07:45 2009
@@ -29,6 +29,7 @@

  #include "codegen-inl.h"
  #include "fast-codegen.h"
+#include "parser.h"

  namespace v8 {
  namespace internal {
@@ -100,8 +101,8 @@

  void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
    // Call the runtime to declare the globals.
+  __ push(esi);  // The context is the first argument.
    __ push(Immediate(pairs));
-  __ push(esi);  // The context is the second argument.
    __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0)));
    __ CallRuntime(Runtime::kDeclareGlobals, 3);
    // Return value is ignored.
@@ -157,8 +158,8 @@
    ASSERT(boilerplate->IsBoilerplate());

    // Create a new closure.
-  __ push(Immediate(boilerplate));
    __ push(esi);
+  __ push(Immediate(boilerplate));
    __ CallRuntime(Runtime::kNewClosure, 2);

    if (expr->location().is_temporary()) {
@@ -190,7 +191,7 @@
        __ mov(Operand(esp, 0), eax);
      } else {
        ASSERT(expr->location().is_nowhere());
-      __ pop(eax);
+      __ add(Operand(esp), Immediate(kPointerSize));
      }

    } else {
@@ -235,6 +236,76 @@
      ASSERT(expr->location().is_nowhere());
    }
  }
+
+
+void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+  Label make_clone;
+
+  // Fetch the function's literals array.
+  __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+  __ mov(ebx, FieldOperand(ebx, JSFunction::kLiteralsOffset));
+  // Check if the literal's boilerplate has been instantiated.
+  int offset =
+      FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
+  __ mov(eax, FieldOperand(ebx, offset));
+  __ cmp(eax, Factory::undefined_value());
+  __ j(not_equal, &make_clone);
+
+  // Instantiate the boilerplate.
+  __ push(ebx);
+  __ push(Immediate(Smi::FromInt(expr->literal_index())));
+  __ push(Immediate(expr->literals()));
+  __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
+
+  __ bind(&make_clone);
+  // Clone the boilerplate.
+  __ push(eax);
+  if (expr->depth() > 1) {
+    __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
+  } else {
+    __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
+  }
+
+  bool result_saved = false;  // Is the result saved to the stack?
+
+  // Emit code to evaluate all the non-constant subexpressions and to store
+  // them into the newly cloned array.
+  ZoneList<Expression*>* subexprs = expr->values();
+  for (int i = 0, len = subexprs->length(); i < len; i++) {
+    Expression* subexpr = subexprs->at(i);
+    // If the subexpression is a literal or a simple materialized literal  
it
+    // is already set in the cloned array.
+    if (subexpr->AsLiteral() != NULL ||
+        CompileTimeValue::IsCompileTimeValue(subexpr)) {
+      continue;
+    }
+
+    if (!result_saved) {
+      __ push(eax);
+      result_saved = true;
+    }
+    Visit(subexpr);
+    ASSERT(subexpr->location().is_temporary());
+
+    // Store the subexpression value in the array's elements.
+    __ pop(eax);  // Subexpression value.
+    __ mov(ebx, Operand(esp, 0));  // Copy of array literal.
+    __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
+    int offset = FixedArray::kHeaderSize + (i * kPointerSize);
+    __ mov(FieldOperand(ebx, offset), eax);
+
+    // Update the write barrier for the array store.
+    __ RecordWrite(ebx, offset, eax, ecx);
+  }
+
+  Location destination = expr->location();
+  if (destination.is_nowhere() && result_saved) {
+    __ add(Operand(esp), Immediate(kPointerSize));
+  } else if (destination.is_temporary() && !result_saved) {
+    __ push(eax);
+  }
+}


  void FastCodeGenerator::VisitAssignment(Assignment* expr) {
@@ -275,7 +346,7 @@
        __ mov(Operand(esp, 0), eax);
      } else {
        ASSERT(destination.is_nowhere());
-      __ pop(eax);
+      __ add(Operand(esp), Immediate(kPointerSize));
      }

    } else {
@@ -339,7 +410,7 @@
      __ mov(Operand(esp, 0), eax);
    } else {
      ASSERT(expr->location().is_nowhere());
-    __ pop(eax);
+    __ add(Operand(esp), Immediate(kPointerSize));
    }
  }

=======================================
--- /branches/bleeding_edge/src/runtime.cc      Wed Oct 21 10:07:43 2009
+++ /branches/bleeding_edge/src/runtime.cc      Thu Oct 22 03:07:45 2009
@@ -577,8 +577,8 @@
    HandleScope scope;
    Handle<GlobalObject> global =  
Handle<GlobalObject>(Top::context()->global());

-  CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
-  Handle<Context> context = args.at<Context>(1);
+  Handle<Context> context = args.at<Context>(0);
+  CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
    bool is_eval = Smi::cast(args[2])->value() == 1;

    // Compute the property attributes. According to ECMA-262, section
@@ -4391,8 +4391,8 @@
  static Object* Runtime_NewClosure(Arguments args) {
    HandleScope scope;
    ASSERT(args.length() == 2);
-  CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
-  CONVERT_ARG_CHECKED(Context, context, 1);
+  CONVERT_ARG_CHECKED(Context, context, 0);
+  CONVERT_ARG_CHECKED(JSFunction, boilerplate, 1);

    Handle<JSFunction> result =
        Factory::NewFunctionFromBoilerplate(boilerplate, context);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Wed Oct 21 02:24:25 2009
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Oct 22 03:07:45 2009
@@ -270,8 +270,8 @@
    frame_->SyncRange(0, frame_->element_count() - 1);

    __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT);
+  frame_->EmitPush(rsi);  // The context is the first argument.
    frame_->EmitPush(kScratchRegister);
-  frame_->EmitPush(rsi);  // The context is the second argument.
    frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0));
    Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
    // Return value is ignored.
@@ -2177,12 +2177,10 @@
    ASSERT(boilerplate->IsBoilerplate());
    frame_->SyncRange(0, frame_->element_count() - 1);

-  // Push the boilerplate on the stack.
-  __ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
-  frame_->EmitPush(kScratchRegister);
-
    // Create a new closure.
    frame_->EmitPush(rsi);
+  __ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
+  frame_->EmitPush(kScratchRegister);
    Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
    frame_->Push(&result);
  }
=======================================
--- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Thu Oct 22 02:29:03  
2009
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Thu Oct 22 03:07:45  
2009
@@ -30,6 +30,7 @@
  #include "codegen-inl.h"
  #include "debug.h"
  #include "fast-codegen.h"
+#include "parser.h"

  namespace v8 {
  namespace internal {
@@ -108,8 +109,8 @@

  void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
    // Call the runtime to declare the globals.
+  __ push(rsi);  // The context is the first argument.
    __ Push(pairs);
-  __ push(rsi);  // The context is the second argument.
    __ Push(Smi::FromInt(is_eval_ ? 1 : 0));
    __ CallRuntime(Runtime::kDeclareGlobals, 3);
    // Return value is ignored.
@@ -174,8 +175,8 @@
    ASSERT(boilerplate->IsBoilerplate());

    // Create a new closure.
-  __ Push(boilerplate);
    __ push(rsi);
+  __ Push(boilerplate);
    __ CallRuntime(Runtime::kNewClosure, 2);

    if (expr->location().is_temporary()) {
@@ -206,7 +207,7 @@
        __ movq(Operand(rsp, 0), rax);
      } else {
        ASSERT(expr->location().is_nowhere());
-      __ pop(rax);
+      __ addq(rsp, Immediate(kPointerSize));
      }

    } else {
@@ -251,6 +252,76 @@
      ASSERT(expr->location().is_nowhere());
    }
  }
+
+
+void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+  Label make_clone;
+
+  // Fetch the function's literals array.
+  __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+  __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset));
+  // Check if the literal's boilerplate has been instantiated.
+  int offset =
+      FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
+  __ movq(rax, FieldOperand(rbx, offset));
+  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+  __ j(not_equal, &make_clone);
+
+  // Instantiate the boilerplate.
+  __ push(rbx);
+  __ Push(Smi::FromInt(expr->literal_index()));
+  __ Push(expr->literals());
+  __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
+
+  __ bind(&make_clone);
+  // Clone the boilerplate.
+  __ push(rax);
+  if (expr->depth() > 1) {
+    __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
+  } else {
+    __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
+  }
+
+  bool result_saved = false;  // Is the result saved to the stack?
+
+  // Emit code to evaluate all the non-constant subexpressions and to store
+  // them into the newly cloned array.
+  ZoneList<Expression*>* subexprs = expr->values();
+  for (int i = 0, len = subexprs->length(); i < len; i++) {
+    Expression* subexpr = subexprs->at(i);
+    // If the subexpression is a literal or a simple materialized literal  
it
+    // is already set in the cloned array.
+    if (subexpr->AsLiteral() != NULL ||
+        CompileTimeValue::IsCompileTimeValue(subexpr)) {
+      continue;
+    }
+
+    if (!result_saved) {
+      __ push(rax);
+      result_saved = true;
+    }
+    Visit(subexpr);
+    ASSERT(subexpr->location().is_temporary());
+
+    // Store the subexpression value in the array's elements.
+    __ pop(rax);  // Subexpression value.
+    __ movq(rbx, Operand(rsp, 0));  // Copy of array literal.
+    __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
+    int offset = FixedArray::kHeaderSize + (i * kPointerSize);
+    __ movq(FieldOperand(rbx, offset), rax);
+
+    // Update the write barrier for the array store.
+    __ RecordWrite(rbx, offset, rax, rcx);
+  }
+
+  Location destination = expr->location();
+  if (destination.is_nowhere() && result_saved) {
+    __ addq(rsp, Immediate(kPointerSize));
+  } else if (destination.is_temporary() && !result_saved) {
+    __ push(rax);
+  }
+}


  void FastCodeGenerator::VisitAssignment(Assignment* expr) {
@@ -290,7 +361,7 @@
      if (destination.is_temporary()) {
        __ movq(Operand(rsp, 0), rax);
      } else {
-      __ pop(rax);
+      __ addq(rsp, Immediate(kPointerSize));
      }
    } else {
      if (source.is_temporary()) {
@@ -352,7 +423,7 @@
      __ movq(Operand(rsp, 0), rax);
    } else {
      ASSERT(expr->location().is_nowhere());
-    __ pop(rax);
+    __ addq(rsp, Immediate(kPointerSize));
    }
  }

=======================================
--- /branches/bleeding_edge/test/mjsunit/compiler/literals.js   Wed Oct 14  
03:24:50 2009
+++ /branches/bleeding_edge/test/mjsunit/compiler/literals.js   Thu Oct 22  
03:07:45 2009
@@ -33,3 +33,20 @@
  assertEquals("abc", eval("'abc'"));

  assertEquals(8, eval("6;'abc';8"));
+
+// Test some materialized array literals.
+assertEquals([1,2,3,4], eval('[1,2,3,4]'));
+assertEquals([[1,2],3,4], eval('[[1,2],3,4]'));
+assertEquals([1,[2,3,4]], eval('[1,[2,3,4]]'));
+
+assertEquals([1,2,3,4], eval('var a=1, b=2; [a,b,3,4]'))
+assertEquals([1,2,3,4], eval('var a=1, b=2, c = [a,b,3,4]; c'));
+
+function double(x) { return x + x; }
+var s = 'var a = 1, b = 2; [double(a), double(b), double(3), double(4)]';
+assertEquals([2,4,6,8], eval(s));
+
+// Test array literals in effect context.
+assertEquals(17, eval('[1,2,3,4]; 17'));
+assertEquals(19, eval('var a=1, b=2; [a,b,3,4]; 19'));
+assertEquals(23, eval('var a=1, b=2; c=23; [a,b,3,4]; c'));

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to