LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- // TODO(danno): Add support for other external array types.
- if (instr->array_type() != kExternalPixelArray) {
- Abort("unsupported load for external array type.");
- return NULL;
- }
-
- ASSERT(instr->representation().IsInteger32());
+ ExternalArrayType array_type = instr->array_type();
+ Representation representation(instr->representation());
+ ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
+ (representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->key()->representation().IsInteger32());
- LOperand* external_pointer =
- UseRegisterAtStart(instr->external_pointer());
- LOperand* key = UseRegisterAtStart(instr->key());
+ LOperand* external_pointer = UseRegister(instr->external_pointer());
+ LOperand* key = UseRegister(instr->key());
LLoadKeyedSpecializedArrayElement* result =
- new LLoadKeyedSpecializedArrayElement(external_pointer,
- key);
- return DefineAsRegister(result);
+ new LLoadKeyedSpecializedArrayElement(external_pointer, key);
+ LInstruction* load_instr = DefineAsRegister(result);
+ // An unsigned int array load might overflow and cause a deopt, make sure it
+ // has an environment.
+ return (array_type == kExternalUnsignedIntArray) ?
+ AssignEnvironment(load_instr) : load_instr;
}
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
- // TODO(danno): Add support for other external array types.
- if (instr->array_type() != kExternalPixelArray) {
- Abort("unsupported store for external array type.");
- return NULL;
- }
-
- ASSERT(instr->value()->representation().IsInteger32());
+ Representation representation(instr->value()->representation());
+ ExternalArrayType array_type = instr->array_type();
+ ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
+ (representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* value = UseTempRegister(instr->value()); // changed by clamp.
+ bool val_is_temp_register = array_type == kExternalPixelArray ||
+ array_type == kExternalFloatArray;
+ LOperand* val = val_is_temp_register
+ ? UseTempRegister(instr->value())
+ : UseRegister(instr->value());
LOperand* key = UseRegister(instr->key());
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
- value);
+ val);
}
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(scratch, ip);
__ b(eq, &done);
- __ LoadRoot(ip, Heap::kExternalPixelArrayMapRootIndex);
- __ cmp(scratch, ip);
- __ b(eq, &done);
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
__ cmp(scratch, ip);
- __ Check(eq, "Check for fast elements failed.");
+ __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
+ __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+ __ sub(scratch, scratch, Operand(FIRST_EXTERNAL_ARRAY_TYPE));
+ __ cmp(scratch, Operand(kExternalArrayTypeCount));
+ __ Check(cc, "Check for fast elements failed.");
__ bind(&done);
}
}
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- ASSERT(instr->array_type() == kExternalPixelArray);
-
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register result = ToRegister(instr->result());
-
- // Load the result.
- __ ldrb(result, MemOperand(external_pointer, key));
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ DwVfpRegister result(ToDoubleRegister(instr->result()));
+ __ add(scratch0(), external_pointer, Operand(key, LSL, 2));
+ __ vldr(result, scratch0(), 0);
+ } else {
+ Register result(ToRegister(instr->result()));
+ __ ldr(result, MemOperand(external_pointer, key, LSL, 2));
+ }
+ } else {
+ Register result(ToRegister(instr->result()));
+ switch (array_type) {
+ case kExternalByteArray:
+ __ ldrsb(result, MemOperand(external_pointer, key));
+ break;
+ case kExternalUnsignedByteArray:
+ case kExternalPixelArray:
+ __ ldrb(result, MemOperand(external_pointer, key));
+ break;
+ case kExternalShortArray:
+ __ ldrsh(result, MemOperand(external_pointer, key, LSL, 1));
+ break;
+ case kExternalUnsignedShortArray:
+ __ ldrh(result, MemOperand(external_pointer, key, LSL, 1));
+ break;
+ case kExternalIntArray:
+ __ ldr(result, MemOperand(external_pointer, key, LSL, 2));
+ break;
+ case kExternalUnsignedIntArray:
+ __ ldr(result, MemOperand(external_pointer, key, LSL, 2));
+ __ cmp(result, Operand(0x80000000));
+ // TODO(danno): we could be more clever here, perhaps having a special
+ // version of the stub that detects if the overflow case actually
+ // happens, and generate code that returns a double rather than int.
+ DeoptimizeIf(cs, instr->environment());
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
+ }
}
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- ASSERT(instr->array_type() == kExternalPixelArray);
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register value = ToRegister(instr->value());
-
- // Clamp the value to [0..255].
- __ Usat(value, 8, Operand(value));
- __ strb(value, MemOperand(external_pointer, key, LSL, 0));
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ DwVfpRegister value(ToDoubleRegister(instr->value()));
+ __ add(scratch0(), external_pointer, Operand(key, LSL, 2));
+ __ vstr(value, scratch0(), 0);
+ } else {
+ Register value(ToRegister(instr->value()));
+ __ str(value, MemOperand(external_pointer, key, LSL, 2));
+ }
+ } else {
+ Register value(ToRegister(instr->value()));
+ switch (array_type) {
+ case kExternalPixelArray:
+ // Clamp the value to [0..255].
+ __ Usat(value, 8, Operand(value));
+ __ strb(value, MemOperand(external_pointer, key));
+ break;
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ strb(value, MemOperand(external_pointer, key));
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ strh(value, MemOperand(external_pointer, key, LSL, 1));
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ __ str(value, MemOperand(external_pointer, key, LSL, 2));
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
+ }
}
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
} else if (is_monomorphic_) {
monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
if (monomorphic_receiver_type_->has_external_array_elements()) {
- SetExternalArrayType(oracle->GetKeyedLoadExternalArrayType(this));
+ set_external_array_type(oracle->GetKeyedLoadExternalArrayType(this));
}
}
}
// Record receiver type for monomorphic keyed loads.
monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
if (monomorphic_receiver_type_->has_external_array_elements()) {
- SetExternalArrayType(oracle->GetKeyedStoreExternalArrayType(this));
+ set_external_array_type(oracle->GetKeyedStoreExternalArrayType(this));
+ }
+ }
+}
+
+
+void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
+ is_monomorphic_ = oracle->StoreIsMonomorphic(this);
+ if (is_monomorphic_) {
+ // Record receiver type for monomorphic keyed loads.
+ monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
+ if (monomorphic_receiver_type_->has_external_array_elements()) {
+ set_external_array_type(oracle->GetKeyedStoreExternalArrayType(this));
}
}
}
Expression() : bitfields_(0) {}
+ virtual int position() const {
+ UNREACHABLE();
+ return 0;
+ }
+
virtual Expression* AsExpression() { return this; }
virtual bool IsTrivial() { return false; }
bitfields_ |= NumBitOpsField::encode(num_bit_ops);
}
+ ExternalArrayType external_array_type() const {
+ return ExternalArrayTypeField::decode(bitfields_);
+ }
+ void set_external_array_type(ExternalArrayType array_type) {
+ bitfields_ &= ~ExternalArrayTypeField::mask();
+ bitfields_ |= ExternalArrayTypeField::encode(array_type);
+ }
+
private:
static const int kMaxNumBitOps = (1 << 5) - 1;
class ToInt32Field : public BitField<bool, 2, 1> {};
class NumBitOpsField : public BitField<int, 3, 5> {};
class LoopConditionField: public BitField<bool, 8, 1> {};
+ class ExternalArrayTypeField: public BitField<ExternalArrayType, 9, 4> {};
};
JumpTarget* body_target() { return &body_target_; }
ZoneList<Statement*>* statements() const { return statements_; }
- int position() { return position_; }
+ int position() const { return position_; }
void set_position(int pos) { position_ = pos; }
int EntryId() { return entry_id_; }
Expression* obj() const { return obj_; }
Expression* key() const { return key_; }
- int position() const { return pos_; }
+ virtual int position() const { return pos_; }
bool is_synthetic() const { return type_ == SYNTHETIC; }
bool IsStringLength() const { return is_string_length_; }
}
bool is_arguments_access() const { return is_arguments_access_; }
- ExternalArrayType GetExternalArrayType() const { return array_type_; }
- void SetExternalArrayType(ExternalArrayType array_type) {
- array_type_ = array_type;
- }
-
// Type feedback information.
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
virtual bool IsMonomorphic() { return is_monomorphic_; }
bool is_function_prototype_ : 1;
bool is_arguments_access_ : 1;
Handle<Map> monomorphic_receiver_type_;
- ExternalArrayType array_type_;
};
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
- int position() { return pos_; }
+ virtual int position() const { return pos_; }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
virtual ZoneMapList* GetReceiverTypes() { return receiver_types_; }
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
- int position() { return pos_; }
+ virtual int position() const { return pos_; }
private:
Expression* expression_;
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
Expression* right() const { return right_; }
- int position() const { return pos_; }
+ virtual int position() const { return pos_; }
// Bailout support.
int RightId() const { return right_id_; }
}
Expression* expression() const { return expression_; }
- int position() const { return pos_; }
+ virtual int position() const { return pos_; }
virtual void MarkAsStatement() { is_prefix_ = true; }
virtual bool IsInlineable() const;
+ void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+ virtual bool IsMonomorphic() { return is_monomorphic_; }
+ virtual Handle<Map> GetMonomorphicReceiverType() {
+ return monomorphic_receiver_type_;
+ }
+
// Bailout support.
int AssignmentId() const { return assignment_id_; }
int CountId() const { return count_id_; }
private:
Token::Value op_;
bool is_prefix_;
+ bool is_monomorphic_;
Expression* expression_;
int pos_;
int assignment_id_;
int count_id_;
+ Handle<Map> monomorphic_receiver_type_;
};
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
Expression* right() const { return right_; }
- int position() const { return pos_; }
+ virtual int position() const { return pos_; }
virtual bool IsInlineable() const;
Token::Value op() const { return op_; }
Expression* target() const { return target_; }
Expression* value() const { return value_; }
- int position() { return pos_; }
+ virtual int position() const { return pos_; }
BinaryOperation* binary_operation() const { return binary_operation_; }
// This check relies on the definition order of token in token.h.
virtual Handle<Map> GetMonomorphicReceiverType() {
return monomorphic_receiver_type_;
}
- ExternalArrayType GetExternalArrayType() const { return array_type_; }
- void SetExternalArrayType(ExternalArrayType array_type) {
- array_type_ = array_type;
- }
// Bailout support.
int CompoundLoadId() const { return compound_load_id_; }
bool is_monomorphic_;
ZoneMapList* receiver_types_;
Handle<Map> monomorphic_receiver_type_;
- ExternalArrayType array_type_;
};
DECLARE_NODE_TYPE(Throw)
Expression* exception() const { return exception_; }
- int position() const { return pos_; }
+ virtual int position() const { return pos_; }
private:
Expression* exception_;
value = Pop();
HValue* key = Pop();
HValue* object = Pop();
-
- if (expr->IsMonomorphic()) {
- Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
- // An object has either fast elements or external array elements, but
- // never both. Pixel array maps that are assigned to pixel array elements
- // are always created with the fast elements flag cleared.
- if (receiver_type->has_external_array_elements()) {
- instr = BuildStoreKeyedSpecializedArrayElement(object,
- key,
- value,
- expr);
- } else if (receiver_type->has_fast_elements()) {
- instr = BuildStoreKeyedFastElement(object, key, value, expr);
- }
- }
- if (instr == NULL) {
- instr = BuildStoreKeyedGeneric(object, key, value);
- }
+ instr = BuildStoreKeyed(object, key, value, expr);
}
-
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
- bool is_fast_elements = prop->IsMonomorphic() &&
- prop->GetMonomorphicReceiverType()->has_fast_elements();
- HInstruction* load = is_fast_elements
- ? BuildLoadKeyedFastElement(obj, key, prop)
- : BuildLoadKeyedGeneric(obj, key);
+ HInstruction* load = BuildLoadKeyed(obj, key, prop);
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId());
PushAndAdd(instr);
if (instr->HasSideEffects()) AddSimulate(operation->id());
- HInstruction* store = is_fast_elements
- ? BuildStoreKeyedFastElement(obj, key, instr, prop)
- : BuildStoreKeyedGeneric(obj, key, instr);
+ expr->RecordTypeFeedback(oracle());
+ HInstruction* store = BuildStoreKeyed(obj, key, instr, expr);
AddInstruction(store);
// Drop the simulated receiver, key, and value. Return the value.
Drop(3);
AddInstruction(external_elements);
HLoadKeyedSpecializedArrayElement* pixel_array_value =
new(zone()) HLoadKeyedSpecializedArrayElement(
- external_elements, key, expr->GetExternalArrayType());
+ external_elements, key, expr->external_array_type());
return pixel_array_value;
}
+HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj,
+ HValue* key,
+ Property* prop) {
+ if (prop->IsMonomorphic()) {
+ Handle<Map> receiver_type(prop->GetMonomorphicReceiverType());
+ // An object has either fast elements or pixel array elements, but never
+ // both. Pixel array maps that are assigned to pixel array elements are
+ // always created with the fast elements flag cleared.
+ if (receiver_type->has_external_array_elements()) {
+ return BuildLoadKeyedSpecializedArrayElement(obj, key, prop);
+ } else if (receiver_type->has_fast_elements()) {
+ return BuildLoadKeyedFastElement(obj, key, prop);
+ }
+ }
+ return BuildLoadKeyedGeneric(obj, key);
+}
+
+
HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
HValue* key,
HValue* value) {
HValue* object,
HValue* key,
HValue* val,
- Assignment* expr) {
+ Expression* expr) {
ASSERT(expr->IsMonomorphic());
AddInstruction(new(zone()) HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
external_elements,
key,
val,
- expr->GetExternalArrayType());
+ expr->external_array_type());
+}
+
+
+HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object,
+ HValue* key,
+ HValue* value,
+ Expression* expr) {
+ if (expr->IsMonomorphic()) {
+ Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
+ // An object has either fast elements or external array elements, but
+ // never both. Pixel array maps that are assigned to pixel array elements
+ // are always created with the fast elements flag cleared.
+ if (receiver_type->has_external_array_elements()) {
+ return BuildStoreKeyedSpecializedArrayElement(object,
+ key,
+ value,
+ expr);
+ } else if (receiver_type->has_fast_elements()) {
+ return BuildStoreKeyedFastElement(object, key, value, expr);
+ }
+ }
+ return BuildStoreKeyedGeneric(object, key, value);
}
HValue* key = Pop();
HValue* obj = Pop();
-
- if (expr->IsMonomorphic()) {
- Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
- // An object has either fast elements or pixel array elements, but never
- // both. Pixel array maps that are assigned to pixel array elements are
- // always created with the fast elements flag cleared.
- if (receiver_type->has_external_array_elements()) {
- instr = BuildLoadKeyedSpecializedArrayElement(obj, key, expr);
- } else if (receiver_type->has_fast_elements()) {
- instr = BuildLoadKeyedFastElement(obj, key, expr);
- }
- }
- if (instr == NULL) {
- instr = BuildLoadKeyedGeneric(obj, key);
- }
+ instr = BuildLoadKeyed(obj, key, expr);
}
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
- bool is_fast_elements = prop->IsMonomorphic() &&
- prop->GetMonomorphicReceiverType()->has_fast_elements();
-
- HInstruction* load = is_fast_elements
- ? BuildLoadKeyedFastElement(obj, key, prop)
- : BuildLoadKeyedGeneric(obj, key);
+ HInstruction* load = BuildLoadKeyed(obj, key, prop);
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CountId());
HInstruction* after = BuildIncrement(before, inc);
AddInstruction(after);
- HInstruction* store = is_fast_elements
- ? BuildStoreKeyedFastElement(obj, key, after, prop)
- : BuildStoreKeyedGeneric(obj, key, after);
+ expr->RecordTypeFeedback(oracle());
+ HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
AddInstruction(store);
// Drop the key from the bailout environment. Overwrite the receiver
HInstruction* BuildLoadKeyedGeneric(HValue* object,
HValue* key);
+ HInstruction* BuildLoadKeyed(HValue* obj,
+ HValue* key,
+ Property* prop);
+
HInstruction* BuildLoadNamed(HValue* object,
Property* prop,
Handle<Map> map,
HValue* object,
HValue* key,
HValue* val,
- Assignment* expr);
+ Expression* expr);
+
+ HInstruction* BuildStoreKeyed(HValue* object,
+ HValue* key,
+ HValue* value,
+ Expression* assignment);
HValue* BuildContextChainWalk(Variable* var);
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
}
-bool TypeFeedbackOracle::StoreIsMonomorphic(Assignment* expr) {
+bool TypeFeedbackOracle::StoreIsMonomorphic(Expression* expr) {
Handle<Object> map_or_code(GetInfo(expr->position()));
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
}
-Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Assignment* expr) {
+Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) {
ASSERT(StoreIsMonomorphic(expr));
Handle<HeapObject> map_or_code(
Handle<HeapObject>::cast(GetInfo(expr->position())));
}
ExternalArrayType TypeFeedbackOracle::GetKeyedStoreExternalArrayType(
- Assignment* expr) {
+ Expression* expr) {
Handle<Object> stub = GetInfo(expr->position());
ASSERT(stub->IsCode());
return Code::cast(*stub)->external_array_type();
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
TypeFeedbackOracle(Handle<Code> code, Handle<Context> global_context);
bool LoadIsMonomorphic(Property* expr);
- bool StoreIsMonomorphic(Assignment* expr);
+ bool StoreIsMonomorphic(Expression* expr);
bool CallIsMonomorphic(Call* expr);
Handle<Map> LoadMonomorphicReceiverType(Property* expr);
- Handle<Map> StoreMonomorphicReceiverType(Assignment* expr);
+ Handle<Map> StoreMonomorphicReceiverType(Expression* expr);
ZoneMapList* LoadReceiverTypes(Property* expr, Handle<String> name);
ZoneMapList* StoreReceiverTypes(Assignment* expr, Handle<String> name);
ZoneMapList* CallReceiverTypes(Call* expr, Handle<String> name);
ExternalArrayType GetKeyedLoadExternalArrayType(Property* expr);
- ExternalArrayType GetKeyedStoreExternalArrayType(Assignment* expr);
+ ExternalArrayType GetKeyedStoreExternalArrayType(Expression* expr);
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
-// Copyright 2007-2009 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
array->set(i, static_cast<ElementType>(i));
}
result = CompileRun("function ee_load_test_func(sum) {"
- " for (var i=0;i<40;++i)"
+ " for (var i = 0; i < 40; ++i)"
" sum += ext_array[i];"
" return sum;"
"}"
// Test crankshaft external array stores
result = CompileRun("function ee_store_test_func(sum) {"
- " for (var i=0;i<40;++i)"
+ " for (var i = 0; i < 40; ++i)"
" sum += ext_array[i] = i;"
" return sum;"
"}"
"sum;");
CHECK_EQ(7800000, result->Int32Value());
+ for (int i = 0; i < kElementCount; i++) {
+ array->set(i, static_cast<ElementType>(i));
+ }
+ // Test complex assignments
+ result = CompileRun("function ee_op_test_complex_func(sum) {"
+ " for (var i = 0; i < 40; ++i) {"
+ " sum += (ext_array[i] += 1);"
+ " sum += (ext_array[i] -= 1);"
+ " } "
+ " return sum;"
+ "}"
+ "sum=0;"
+ "for (var i=0;i<10000;++i) {"
+ " sum=ee_op_test_complex_func(sum);"
+ "}"
+ "sum;");
+ CHECK_EQ(16000000, result->Int32Value());
+
+ // Test count operations
+ result = CompileRun("function ee_op_test_count_func(sum) {"
+ " for (var i = 0; i < 40; ++i) {"
+ " sum += (++ext_array[i]);"
+ " sum += (--ext_array[i]);"
+ " } "
+ " return sum;"
+ "}"
+ "sum=0;"
+ "for (var i=0;i<10000;++i) {"
+ " sum=ee_op_test_count_func(sum);"
+ "}"
+ "sum;");
+ CHECK_EQ(16000000, result->Int32Value());
+
result = CompileRun("ext_array[3] = 33;"
"delete ext_array[3];"
"ext_array[3];");