DontDelete = 1 << 2
};
+enum ExternalArrayType {
+ kExternalByteArray = 1,
+ kExternalUnsignedByteArray,
+ kExternalShortArray,
+ kExternalUnsignedShortArray,
+ kExternalIntArray,
+ kExternalUnsignedIntArray,
+ kExternalFloatArray
+};
+
/**
* A JavaScript object (ECMA-262, 4.3.3)
*/
*/
void SetIndexedPropertiesToPixelData(uint8_t* data, int length);
+ /**
+ * Set the backing store of the indexed properties to be managed by the
+ * embedding layer. Access to the indexed properties will follow the rules
+ * spelled out for the CanvasArray subtypes in the WebGL specification.
+ * Note: The embedding program still owns the data and needs to ensure that
+ * the backing store is preserved while V8 has a reference.
+ */
+ void SetIndexedPropertiesToExternalArrayData(void* data,
+ ExternalArrayType array_type,
+ int number_of_elements);
+
static Local<Object> New();
static inline Object* Cast(Value* obj);
private:
}
+void v8::Object::SetIndexedPropertiesToExternalArrayData(
+ void* data,
+ ExternalArrayType array_type,
+ int length) {
+ ON_BAILOUT("v8::SetIndexedPropertiesToExternalArrayData()", return);
+ ENTER_V8;
+ HandleScope scope;
+ if (!ApiCheck(length <= i::ExternalArray::kMaxLength,
+ "v8::Object::SetIndexedPropertiesToExternalArrayData()",
+ "length exceeds max acceptable value")) {
+ return;
+ }
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ if (!ApiCheck(!self->IsJSArray(),
+ "v8::Object::SetIndexedPropertiesToExternalArrayData()",
+ "JSArray is not supported")) {
+ return;
+ }
+ i::Handle<i::ExternalArray> array =
+ i::Factory::NewExternalArray(length, array_type, data);
+ self->set_elements(*array);
+}
+
+
Local<v8::Object> Function::NewInstance() const {
return NewInstance(0, NULL);
}
}
+void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ // TODO(476): port specialized code.
+ GenerateGeneric(masm);
+}
+
+
void KeyedStoreIC::Generate(MacroAssembler* masm,
const ExternalReference& f) {
// ---------- S t a t e --------------
}
+void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ // TODO(476): port specialized code.
+ GenerateGeneric(masm);
+}
+
+
void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- r0 : value
}
+static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
+}
+
+
+static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
+ MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
+}
+
+
+static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
+}
+
+
+static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
+ MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
+}
+
+
+static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
+}
+
+
+static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
+ MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
+}
+
+
+static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
+ KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
+}
+
+
static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
KeyedLoadIC::GeneratePreMonomorphic(masm);
}
}
+static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
+}
+
+
+static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
+ MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
+}
+
+
+static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
+}
+
+
+static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
+ MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
+}
+
+
+static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
+}
+
+
+static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
+ MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
+}
+
+
+static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
+ KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
+}
+
+
static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
KeyedStoreIC::GenerateExtendStorage(masm);
}
// Define list of builtins implemented in assembly.
-#define BUILTIN_LIST_A(V) \
- V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \
- V(JSConstructCall, BUILTIN, UNINITIALIZED) \
- V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \
- V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \
- V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \
- \
- V(LoadIC_Miss, BUILTIN, UNINITIALIZED) \
- V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \
- V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \
- V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \
- \
- V(StoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \
- V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \
- \
- V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED) \
- V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \
- V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
- \
- V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \
- V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
- V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
- \
- V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
- V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
- \
- V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \
- V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \
- \
- /* Uses KeyedLoadIC_Initialize; must be after in list. */ \
- V(FunctionCall, BUILTIN, UNINITIALIZED) \
- V(FunctionApply, BUILTIN, UNINITIALIZED) \
- \
- V(ArrayCode, BUILTIN, UNINITIALIZED) \
+#define BUILTIN_LIST_A(V) \
+ V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \
+ V(JSConstructCall, BUILTIN, UNINITIALIZED) \
+ V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \
+ V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \
+ V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \
+ \
+ V(LoadIC_Miss, BUILTIN, UNINITIALIZED) \
+ V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \
+ V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \
+ V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \
+ \
+ V(StoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \
+ V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \
+ \
+ V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED) \
+ V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \
+ V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
+ V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
+ V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \
+ V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
+ V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
+ \
+ V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \
+ V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
+ V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalUnsignedByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalUnsignedShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalIntArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalUnsignedIntArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ V(KeyedLoadIC_ExternalFloatArray, KEYED_LOAD_IC, MEGAMORPHIC) \
+ \
+ V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
+ V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
+ \
+ V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \
+ V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalByteArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalUnsignedByteArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalShortArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalUnsignedShortArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalIntArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalUnsignedIntArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ V(KeyedStoreIC_ExternalFloatArray, KEYED_STORE_IC, MEGAMORPHIC) \
+ \
+ /* Uses KeyedLoadIC_Initialize; must be after in list. */ \
+ V(FunctionCall, BUILTIN, UNINITIALIZED) \
+ V(FunctionApply, BUILTIN, UNINITIALIZED) \
+ \
+ V(ArrayCode, BUILTIN, UNINITIALIZED) \
V(ArrayConstructCode, BUILTIN, UNINITIALIZED)
#ifdef ENABLE_DEBUGGER_SUPPORT
}
+Handle<ExternalArray> Factory::NewExternalArray(int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
+ PretenureFlag pretenure) {
+ ASSERT(0 <= length);
+ CALL_HEAP_FUNCTION(Heap::AllocateExternalArray(length,
+ array_type,
+ external_pointer,
+ pretenure), ExternalArray);
+}
+
+
Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map);
}
}
+Handle<Object> Factory::NewIndexError(uint32_t index) {
+ Handle<Object> indexHandle = Handle<Object>(Heap::NumberFromUint32(index));
+ return NewRangeError("invalid_array_index",
+ HandleVector<Object>(&indexHandle,
+ 1));
+}
+
+
Handle<Object> Factory::NewSyntaxError(const char* type, Handle<JSArray> args) {
return NewError("MakeSyntaxError", type, args);
}
static Handle<ByteArray> NewByteArray(int length,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<PixelArray> NewPixelArray(int length,
+ static Handle<PixelArray> NewPixelArray(
+ int length,
uint8_t* external_pointer,
PretenureFlag pretenure = NOT_TENURED);
+ static Handle<ExternalArray> NewExternalArray(
+ int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
+ PretenureFlag pretenure = NOT_TENURED);
+
static Handle<Map> NewMap(InstanceType type, int instance_size);
static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
Vector< Handle<Object> > args);
static Handle<Object> NewRangeError(Handle<String> message);
+ static Handle<Object> NewIndexError(uint32_t index);
+
static Handle<Object> NewSyntaxError(const char* type, Handle<JSArray> args);
static Handle<Object> NewSyntaxError(Handle<String> message);
Handle<Object> SetElement(Handle<JSObject> object,
uint32_t index,
Handle<Object> value) {
- if (object->HasPixelElements()) {
+ if (object->HasPixelElements() || object->HasExternalArrayElements()) {
if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
bool has_exception;
Handle<Object> number = Execution::ToNumber(value, &has_exception);
if (obj->IsFailure()) return false;
set_pixel_array_map(Map::cast(obj));
+ obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_byte_array_map(Map::cast(obj));
+
+ obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_unsigned_byte_array_map(Map::cast(obj));
+
+ obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_short_array_map(Map::cast(obj));
+
+ obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_unsigned_short_array_map(Map::cast(obj));
+
+ obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_int_array_map(Map::cast(obj));
+
+ obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_unsigned_int_array_map(Map::cast(obj));
+
+ obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_external_float_array_map(Map::cast(obj));
+
obj = AllocateMap(CODE_TYPE, Code::kHeaderSize);
if (obj->IsFailure()) return false;
set_code_map(Map::cast(obj));
}
+Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
+ return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
+}
+
+
+Heap::RootListIndex Heap::RootIndexForExternalArrayType(
+ ExternalArrayType array_type) {
+ switch (array_type) {
+ case kExternalByteArray:
+ return kExternalByteArrayMapRootIndex;
+ case kExternalUnsignedByteArray:
+ return kExternalUnsignedByteArrayMapRootIndex;
+ case kExternalShortArray:
+ return kExternalShortArrayMapRootIndex;
+ case kExternalUnsignedShortArray:
+ return kExternalUnsignedShortArrayMapRootIndex;
+ case kExternalIntArray:
+ return kExternalIntArrayMapRootIndex;
+ case kExternalUnsignedIntArray:
+ return kExternalUnsignedIntArrayMapRootIndex;
+ case kExternalFloatArray:
+ return kExternalFloatArrayMapRootIndex;
+ default:
+ UNREACHABLE();
+ return kUndefinedValueRootIndex;
+ }
+}
+
+
Object* Heap::NewNumberFromDouble(double value, PretenureFlag pretenure) {
return SmiOrNumberFromDouble(value,
true /* number object must be new */,
}
+Object* Heap::AllocateExternalArray(int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
+ PretenureFlag pretenure) {
+ AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+
+ // New space can't cope with forced allocation.
+ if (always_allocate()) space = OLD_DATA_SPACE;
+
+ Object* result = AllocateRaw(ExternalArray::kAlignedSize,
+ space,
+ OLD_DATA_SPACE);
+
+ if (result->IsFailure()) return result;
+
+ reinterpret_cast<ExternalArray*>(result)->set_map(
+ MapForExternalArrayType(array_type));
+ reinterpret_cast<ExternalArray*>(result)->set_length(length);
+ reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
+ external_pointer);
+
+ return result;
+}
+
+
Object* Heap::CreateCode(const CodeDesc& desc,
ZoneScopeInfo* sinfo,
Code::Flags flags,
V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap) \
V(Map, byte_array_map, ByteArrayMap) \
V(Map, pixel_array_map, PixelArrayMap) \
+ V(Map, external_byte_array_map, ExternalByteArrayMap) \
+ V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \
+ V(Map, external_short_array_map, ExternalShortArrayMap) \
+ V(Map, external_unsigned_short_array_map, ExternalUnsignedShortArrayMap) \
+ V(Map, external_int_array_map, ExternalIntArrayMap) \
+ V(Map, external_unsigned_int_array_map, ExternalUnsignedIntArrayMap) \
+ V(Map, external_float_array_map, ExternalFloatArrayMap) \
V(Map, context_map, ContextMap) \
V(Map, catch_context_map, CatchContextMap) \
V(Map, code_map, CodeMap) \
uint8_t* external_pointer,
PretenureFlag pretenure);
+ // Allocates an external array of the specified length and type.
+ // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+ // failed.
+ // Please note this does not perform a garbage collection.
+ static Object* AllocateExternalArray(int length,
+ ExternalArrayType array_type,
+ void* external_pointer,
+ PretenureFlag pretenure);
+
// Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
static Object* NumberToString(Object* number);
+ static Map* MapForExternalArrayType(ExternalArrayType array_type);
+ static RootListIndex RootIndexForExternalArrayType(
+ ExternalArrayType array_type);
+
private:
static int semispace_size_;
static int initial_semispace_size_;
// either operand is not a number. Operands are in edx and eax.
// Leaves operands unchanged.
static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers);
- // Allocate a heap number in new space with undefined value.
- // Returns tagged pointer in eax, or jumps to need_gc if new space is full.
- static void AllocateHeapNumber(MacroAssembler* masm,
- Label* need_gc,
- Register scratch1,
- Register scratch2,
- Register result);
};
Result scratch1 = allocator()->Allocate();
Result scratch2 = allocator()->Allocate();
Result heap_number = allocator()->Allocate();
- FloatingPointHelper::AllocateHeapNumber(masm_,
- call_runtime.entry_label(),
- scratch1.reg(),
- scratch2.reg(),
- heap_number.reg());
+ __ AllocateHeapNumber(heap_number.reg(),
+ scratch1.reg(),
+ scratch2.reg(),
+ call_runtime.entry_label());
scratch1.Unuse();
scratch2.Unuse();
case NO_OVERWRITE: {
// Allocate a heap number for the result. Keep eax and edx intact
// for the possible runtime call.
- FloatingPointHelper::AllocateHeapNumber(masm,
- &call_runtime,
- ecx,
- no_reg,
- ebx);
+ __ AllocateHeapNumber(ebx, ecx, no_reg, &call_runtime);
// Now eax can be overwritten losing one of the arguments as we are
// now done and will not need it any more.
__ mov(eax, ebx);
case NO_OVERWRITE:
// Allocate a heap number for the result. Keep eax and edx intact
// for the possible runtime call.
- FloatingPointHelper::AllocateHeapNumber(masm,
- &call_runtime,
- ecx,
- no_reg,
- ebx);
+ __ AllocateHeapNumber(ebx, ecx, no_reg, &call_runtime);
// Now eax can be overwritten losing one of the arguments as we are
// now done and will not need it any more.
__ mov(eax, ebx);
__ j(not_zero, &skip_allocation, not_taken);
// Fall through!
case NO_OVERWRITE:
- FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
- ecx, edx, eax);
+ __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
__ bind(&skip_allocation);
break;
default: UNREACHABLE();
}
-void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
- Label* need_gc,
- Register scratch1,
- Register scratch2,
- Register result) {
- // Allocate heap number in new space.
- __ AllocateInNewSpace(HeapNumber::kSize,
- result,
- scratch1,
- scratch2,
- need_gc,
- TAG_OBJECT);
-
- // Set the map.
- __ mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
-}
-
-
void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
Register number) {
Label load_smi, done;
} else {
__ mov(edx, Operand(eax));
// edx: operand
- FloatingPointHelper::AllocateHeapNumber(masm, &undo, ebx, ecx, eax);
+ __ AllocateHeapNumber(eax, ebx, ecx, &undo);
// eax: allocated 'empty' number
__ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
__ xor_(ecx, HeapNumber::kSignMask); // Flip sign.
// Slow case: Load name and receiver from stack and jump to runtime.
__ bind(&slow);
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
- KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
+ Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
__ bind(&check_string);
// The key is not a smi.
}
+void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ GenerateGeneric(masm);
+}
+
+
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
// ebx: index (as a smi)
__ j(below, &fast, taken);
- // Slow case: Push extra copies of the arguments (3).
+ // Slow case: call runtime.
__ bind(&slow);
- __ pop(ecx);
- __ push(Operand(esp, 1 * kPointerSize));
- __ push(Operand(esp, 1 * kPointerSize));
- __ push(eax);
- __ push(ecx);
- // Do tail-call to runtime routine.
- __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
+ Generate(masm, ExternalReference(Runtime::kSetProperty));
// Check whether the elements is a pixel array.
// eax: value
}
+void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ GenerateGeneric(masm);
+}
+
+
// Defined in ic.cc.
Object* CallIC_Miss(Arguments args);
}
+void MacroAssembler::AllocateHeapNumber(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ // Allocate heap number in new space.
+ AllocateInNewSpace(HeapNumber::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map.
+ mov(FieldOperand(result, HeapObject::kMapOffset),
+ Immediate(Factory::heap_number_map()));
+}
+
+
void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
Register result,
Register op,
// un-done.
void UndoAllocationInNewSpace(Register object);
+ // Allocate a heap number in new space with undefined value. The
+ // register scratch2 can be passed as no_reg; the others must be
+ // valid registers. Returns tagged pointer in result register, or
+ // jumps to gc_required if new space is full.
+ void AllocateHeapNumber(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+
// ---------------------------------------------------------------------------
// Support functions.
}
+Code* KeyedLoadIC::external_array_stub(JSObject::ElementsKind elements_kind) {
+ switch (elements_kind) {
+ case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedLoadIC_ExternalByteArray);
+ case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedByteArray);
+ case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedLoadIC_ExternalShortArray);
+ case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ return Builtins::builtin(
+ Builtins::KeyedLoadIC_ExternalUnsignedShortArray);
+ case JSObject::EXTERNAL_INT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedLoadIC_ExternalIntArray);
+ case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedIntArray);
+ case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedLoadIC_ExternalFloatArray);
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+}
+
+
+Code* KeyedStoreIC::external_array_stub(JSObject::ElementsKind elements_kind) {
+ switch (elements_kind) {
+ case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedStoreIC_ExternalByteArray);
+ case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ return Builtins::builtin(
+ Builtins::KeyedStoreIC_ExternalUnsignedByteArray);
+ case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedStoreIC_ExternalShortArray);
+ case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ return Builtins::builtin(
+ Builtins::KeyedStoreIC_ExternalUnsignedShortArray);
+ case JSObject::EXTERNAL_INT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedStoreIC_ExternalIntArray);
+ case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedStoreIC_ExternalUnsignedIntArray);
+ case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ return Builtins::builtin(Builtins::KeyedStoreIC_ExternalFloatArray);
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+}
+
+
static bool HasInterceptorGetter(JSObject* object) {
return !object->GetNamedInterceptor()->getter()->IsUndefined();
}
bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
if (use_ic) {
- set_target(generic_stub());
+ Code* stub = generic_stub();
+ if (object->IsJSObject()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->HasExternalArrayElements()) {
+ stub = external_array_stub(receiver->GetElementsKind());
+ }
+ }
+ set_target(stub);
// For JSObjects that are not value wrappers and that do not have
// indexed interceptors, we initialize the inlined fast case (if
// present) by patching the inlined map check.
bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
ASSERT(!(use_ic && object->IsJSGlobalProxy()));
- if (use_ic) set_target(generic_stub());
+ if (use_ic) {
+ Code* stub = generic_stub();
+ if (object->IsJSObject()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->HasExternalArrayElements()) {
+ stub = external_array_stub(receiver->GetElementsKind());
+ }
+ }
+ set_target(stub);
+ }
// Set the property.
return Runtime::SetObjectProperty(object, key, value, NONE);
static void GeneratePreMonomorphic(MacroAssembler* masm);
static void GenerateGeneric(MacroAssembler* masm);
+ // Generators for external array types. See objects.h.
+ // These are similar to the generic IC; they optimize the case of
+ // operating upon external array types but fall back to the runtime
+ // for all other types.
+ static void GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type);
+
// Clear the use of the inlined version.
static void ClearInlinedVersion(Address address);
static Code* pre_monomorphic_stub() {
return Builtins::builtin(Builtins::KeyedLoadIC_PreMonomorphic);
}
+ static Code* external_array_stub(JSObject::ElementsKind elements_kind);
static void Clear(Address address, Code* target);
static void GenerateGeneric(MacroAssembler* masm);
static void GenerateExtendStorage(MacroAssembler* masm);
+ // Generators for external array types. See objects.h.
+ // These are similar to the generic IC; they optimize the case of
+ // operating upon external array types but fall back to the runtime
+ // for all other types.
+ static void GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type);
+
// Clear the inlined version so the IC is always hit.
static void ClearInlinedVersion(Address address);
static Code* generic_stub() {
return Builtins::builtin(Builtins::KeyedStoreIC_Generic);
}
+ static Code* external_array_stub(JSObject::ElementsKind elements_kind);
static void Clear(Address address, Code* target);
reduce_no_initial: "Reduce of empty array with no initial value",
// RangeError
invalid_array_length: "Invalid array length",
+ invalid_array_index: "Invalid array index %0", // Currently for CanvasArray types only
stack_overflow: "Maximum call stack size exceeded",
apply_overflow: "Function.prototype.apply cannot support %0 arguments",
// SyntaxError
}
+void ExternalByteArray::ExternalByteArrayPrint() {
+ PrintF("external byte array");
+}
+
+
+void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint() {
+ PrintF("external unsigned byte array");
+}
+
+
+void ExternalShortArray::ExternalShortArrayPrint() {
+ PrintF("external short array");
+}
+
+
+void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint() {
+ PrintF("external unsigned short array");
+}
+
+
+void ExternalIntArray::ExternalIntArrayPrint() {
+ PrintF("external int array");
+}
+
+
+void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint() {
+ PrintF("external unsigned int array");
+}
+
+
+void ExternalFloatArray::ExternalFloatArrayPrint() {
+ PrintF("external float array");
+}
+
+
void ByteArray::ByteArrayVerify() {
ASSERT(IsByteArray());
}
}
+void ExternalByteArray::ExternalByteArrayVerify() {
+ ASSERT(IsExternalByteArray());
+}
+
+
+void ExternalUnsignedByteArray::ExternalUnsignedByteArrayVerify() {
+ ASSERT(IsExternalUnsignedByteArray());
+}
+
+
+void ExternalShortArray::ExternalShortArrayVerify() {
+ ASSERT(IsExternalShortArray());
+}
+
+
+void ExternalUnsignedShortArray::ExternalUnsignedShortArrayVerify() {
+ ASSERT(IsExternalUnsignedShortArray());
+}
+
+
+void ExternalIntArray::ExternalIntArrayVerify() {
+ ASSERT(IsExternalIntArray());
+}
+
+
+void ExternalUnsignedIntArray::ExternalUnsignedIntArrayVerify() {
+ ASSERT(IsExternalUnsignedIntArray());
+}
+
+
+void ExternalFloatArray::ExternalFloatArrayVerify() {
+ ASSERT(IsExternalFloatArray());
+}
+
+
void JSObject::PrintProperties() {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
}
break;
}
+ case EXTERNAL_BYTE_ELEMENTS: {
+ ExternalByteArray* p = ExternalByteArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ }
+ break;
+ }
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ ExternalUnsignedByteArray* p =
+ ExternalUnsignedByteArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ }
+ break;
+ }
+ case EXTERNAL_SHORT_ELEMENTS: {
+ ExternalShortArray* p = ExternalShortArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ }
+ break;
+ }
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ ExternalUnsignedShortArray* p =
+ ExternalUnsignedShortArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ }
+ break;
+ }
+ case EXTERNAL_INT_ELEMENTS: {
+ ExternalIntArray* p = ExternalIntArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ }
+ break;
+ }
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ ExternalUnsignedIntArray* p =
+ ExternalUnsignedIntArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ }
+ break;
+ }
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ ExternalFloatArray* p = ExternalFloatArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %f\n", i, p->get(i));
+ }
+ break;
+ }
case DICTIONARY_ELEMENTS:
elements()->Print();
break;
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
+ case EXTERNAL_BYTE_ARRAY_TYPE: return "EXTERNAL_BYTE_ARRAY";
+ case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
+ return "EXTERNAL_UNSIGNED_BYTE_ARRAY";
+ case EXTERNAL_SHORT_ARRAY_TYPE: return "EXTERNAL_SHORT_ARRAY";
+ case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
+ return "EXTERNAL_UNSIGNED_SHORT_ARRAY";
+ case EXTERNAL_INT_ARRAY_TYPE: return "EXTERNAL_INT_ARRAY";
+ case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
+ return "EXTERNAL_UNSIGNED_INT_ARRAY";
+ case EXTERNAL_FLOAT_ARRAY_TYPE: return "EXTERNAL_FLOAT_ARRAY";
case FILLER_TYPE: return "FILLER";
case JS_OBJECT_TYPE: return "JS_OBJECT";
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT";
}
+bool Object::IsExternalArray() {
+ if (!Object::IsHeapObject())
+ return false;
+ InstanceType instance_type =
+ HeapObject::cast(this)->map()->instance_type();
+ return (instance_type >= EXTERNAL_BYTE_ARRAY_TYPE &&
+ instance_type <= EXTERNAL_FLOAT_ARRAY_TYPE);
+}
+
+
+bool Object::IsExternalByteArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_BYTE_ARRAY_TYPE;
+}
+
+
+bool Object::IsExternalUnsignedByteArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE;
+}
+
+
+bool Object::IsExternalShortArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_SHORT_ARRAY_TYPE;
+}
+
+
+bool Object::IsExternalUnsignedShortArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE;
+}
+
+
+bool Object::IsExternalIntArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_INT_ARRAY_TYPE;
+}
+
+
+bool Object::IsExternalUnsignedIntArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_UNSIGNED_INT_ARRAY_TYPE;
+}
+
+
+bool Object::IsExternalFloatArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_FLOAT_ARRAY_TYPE;
+}
+
+
bool Object::IsFailure() {
return HAS_FAILURE_TAG(this);
}
Array* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
// In the assert below Dictionary is covered under FixedArray.
- ASSERT(array->IsFixedArray() || array->IsPixelArray());
+ ASSERT(array->IsFixedArray() || array->IsPixelArray() ||
+ array->IsExternalArray());
return reinterpret_cast<Array*>(array);
}
void JSObject::set_elements(Array* value, WriteBarrierMode mode) {
// In the assert below Dictionary is covered under FixedArray.
- ASSERT(value->IsFixedArray() || value->IsPixelArray());
+ ASSERT(value->IsFixedArray() || value->IsPixelArray() ||
+ value->IsExternalArray());
WRITE_FIELD(this, kElementsOffset, value);
CONDITIONAL_WRITE_BARRIER(this, kElementsOffset, mode);
}
CAST_ACCESSOR(Proxy)
CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(PixelArray)
+CAST_ACCESSOR(ExternalArray)
+CAST_ACCESSOR(ExternalByteArray)
+CAST_ACCESSOR(ExternalUnsignedByteArray)
+CAST_ACCESSOR(ExternalShortArray)
+CAST_ACCESSOR(ExternalUnsignedShortArray)
+CAST_ACCESSOR(ExternalIntArray)
+CAST_ACCESSOR(ExternalUnsignedIntArray)
+CAST_ACCESSOR(ExternalFloatArray)
CAST_ACCESSOR(Struct)
}
+void* ExternalArray::external_pointer() {
+ intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset);
+ return reinterpret_cast<void*>(ptr);
+}
+
+
+void ExternalArray::set_external_pointer(void* value, WriteBarrierMode mode) {
+ intptr_t ptr = reinterpret_cast<intptr_t>(value);
+ WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr);
+}
+
+
+int8_t ExternalByteArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ int8_t* ptr = static_cast<int8_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalByteArray::set(int index, int8_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ int8_t* ptr = static_cast<int8_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+uint8_t ExternalUnsignedByteArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint8_t* ptr = static_cast<uint8_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalUnsignedByteArray::set(int index, uint8_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint8_t* ptr = static_cast<uint8_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+int16_t ExternalShortArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ int16_t* ptr = static_cast<int16_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalShortArray::set(int index, int16_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ int16_t* ptr = static_cast<int16_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+uint16_t ExternalUnsignedShortArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint16_t* ptr = static_cast<uint16_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalUnsignedShortArray::set(int index, uint16_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint16_t* ptr = static_cast<uint16_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+int32_t ExternalIntArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ int32_t* ptr = static_cast<int32_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalIntArray::set(int index, int32_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ int32_t* ptr = static_cast<int32_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+uint32_t ExternalUnsignedIntArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint32_t* ptr = static_cast<uint32_t*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalUnsignedIntArray::set(int index, uint32_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint32_t* ptr = static_cast<uint32_t*>(external_pointer());
+ ptr[index] = value;
+}
+
+
+float ExternalFloatArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ float* ptr = static_cast<float*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalFloatArray::set(int index, float value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ float* ptr = static_cast<float*>(external_pointer());
+ ptr[index] = value;
+}
+
+
int Map::instance_size() {
return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2;
}
ASSERT(array->IsDictionary());
return DICTIONARY_ELEMENTS;
}
+ if (array->IsExternalArray()) {
+ switch (array->map()->instance_type()) {
+ case EXTERNAL_BYTE_ARRAY_TYPE:
+ return EXTERNAL_BYTE_ELEMENTS;
+ case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
+ return EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+ case EXTERNAL_SHORT_ARRAY_TYPE:
+ return EXTERNAL_SHORT_ELEMENTS;
+ case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
+ return EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+ case EXTERNAL_INT_ARRAY_TYPE:
+ return EXTERNAL_INT_ELEMENTS;
+ case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
+ return EXTERNAL_UNSIGNED_INT_ELEMENTS;
+ default:
+ ASSERT(array->map()->instance_type() == EXTERNAL_FLOAT_ARRAY_TYPE);
+ return EXTERNAL_FLOAT_ELEMENTS;
+ }
+ }
ASSERT(array->IsPixelArray());
return PIXEL_ELEMENTS;
}
}
+bool JSObject::HasExternalArrayElements() {
+ return (HasExternalByteElements() ||
+ HasExternalUnsignedByteElements() ||
+ HasExternalShortElements() ||
+ HasExternalUnsignedShortElements() ||
+ HasExternalIntElements() ||
+ HasExternalUnsignedIntElements() ||
+ HasExternalFloatElements());
+}
+
+
+bool JSObject::HasExternalByteElements() {
+ return GetElementsKind() == EXTERNAL_BYTE_ELEMENTS;
+}
+
+
+bool JSObject::HasExternalUnsignedByteElements() {
+ return GetElementsKind() == EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+}
+
+
+bool JSObject::HasExternalShortElements() {
+ return GetElementsKind() == EXTERNAL_SHORT_ELEMENTS;
+}
+
+
+bool JSObject::HasExternalUnsignedShortElements() {
+ return GetElementsKind() == EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+}
+
+
+bool JSObject::HasExternalIntElements() {
+ return GetElementsKind() == EXTERNAL_INT_ELEMENTS;
+}
+
+
+bool JSObject::HasExternalUnsignedIntElements() {
+ return GetElementsKind() == EXTERNAL_UNSIGNED_INT_ELEMENTS;
+}
+
+
+bool JSObject::HasExternalFloatElements() {
+ return GetElementsKind() == EXTERNAL_FLOAT_ELEMENTS;
+}
+
+
bool JSObject::HasNamedInterceptor() {
return map()->has_named_interceptor();
}
case PIXEL_ARRAY_TYPE:
accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length());
break;
+ case EXTERNAL_BYTE_ARRAY_TYPE:
+ accumulator->Add("<ExternalByteArray[%u]>",
+ ExternalByteArray::cast(this)->length());
+ break;
+ case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
+ accumulator->Add("<ExternalUnsignedByteArray[%u]>",
+ ExternalUnsignedByteArray::cast(this)->length());
+ break;
+ case EXTERNAL_SHORT_ARRAY_TYPE:
+ accumulator->Add("<ExternalShortArray[%u]>",
+ ExternalShortArray::cast(this)->length());
+ break;
+ case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
+ accumulator->Add("<ExternalUnsignedShortArray[%u]>",
+ ExternalUnsignedShortArray::cast(this)->length());
+ break;
+ case EXTERNAL_INT_ARRAY_TYPE:
+ accumulator->Add("<ExternalIntArray[%u]>",
+ ExternalIntArray::cast(this)->length());
+ break;
+ case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
+ accumulator->Add("<ExternalUnsignedIntArray[%u]>",
+ ExternalUnsignedIntArray::cast(this)->length());
+ break;
+ case EXTERNAL_FLOAT_ARRAY_TYPE:
+ accumulator->Add("<ExternalFloatArray[%u]>",
+ ExternalFloatArray::cast(this)->length());
+ break;
case SHARED_FUNCTION_INFO_TYPE:
accumulator->Add("<SharedFunctionInfo>");
break;
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
case PIXEL_ARRAY_TYPE:
+ case EXTERNAL_BYTE_ARRAY_TYPE:
+ case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
+ case EXTERNAL_SHORT_ARRAY_TYPE:
+ case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
+ case EXTERNAL_INT_ARRAY_TYPE:
+ case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
+ case EXTERNAL_FLOAT_ARRAY_TYPE:
break;
case SHARED_FUNCTION_INFO_TYPE: {
SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
Object* JSObject::NormalizeElements() {
- ASSERT(!HasPixelElements());
+ ASSERT(!HasPixelElements() && !HasExternalArrayElements());
if (HasDictionaryElements()) return this;
// Get number of entries.
Object* JSObject::DeleteElementPostInterceptor(uint32_t index,
DeleteMode mode) {
- ASSERT(!HasPixelElements());
+ ASSERT(!HasPixelElements() && !HasExternalArrayElements());
switch (GetElementsKind()) {
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
}
break;
}
- case PIXEL_ELEMENTS: {
- // Pixel elements cannot be deleted. Just silently ignore here.
+ case PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ // Pixel and external array elements cannot be deleted. Just
+ // silently ignore here.
break;
- }
case DICTIONARY_ELEMENTS: {
NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindEntry(index);
// Check if the object is among the indexed properties.
switch (GetElementsKind()) {
case PIXEL_ELEMENTS:
- // Raw pixels do not reference other objects.
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ // Raw pixels and external arrays do not reference other
+ // objects.
break;
case FAST_ELEMENTS: {
int length = IsJSArray() ?
case FAST_ELEMENTS:
break;
case PIXEL_ELEMENTS:
- // Ignore getters and setters on pixel elements.
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ // Ignore getters and setters on pixel and external array
+ // elements.
return Heap::undefined_value();
case DICTIONARY_ELEMENTS: {
// Lookup the index.
Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
- ASSERT(!array->HasPixelElements());
+ ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements());
switch (array->GetElementsKind()) {
case JSObject::FAST_ELEMENTS:
return UnionOfKeys(FixedArray::cast(array->elements()));
void JSObject::SetFastElements(FixedArray* elems) {
- // We should never end in here with a pixel array.
- ASSERT(!HasPixelElements());
+ // We should never end in here with a pixel or external array.
+ ASSERT(!HasPixelElements() && !HasExternalArrayElements());
#ifdef DEBUG
// Check the provided array is filled with the_hole.
uint32_t len = static_cast<uint32_t>(elems->length());
Object* JSObject::SetSlowElements(Object* len) {
- // We should never end in here with a pixel array.
- ASSERT(!HasPixelElements());
+ // We should never end in here with a pixel or external array.
+ ASSERT(!HasPixelElements() && !HasExternalArrayElements());
uint32_t new_length = static_cast<uint32_t>(len->Number());
Object* JSObject::SetElementsLength(Object* len) {
- // We should never end in here with a pixel array.
- ASSERT(!HasPixelElements());
+ // We should never end in here with a pixel or external array.
+ ASSERT(!HasPixelElements() && !HasExternalArrayElements());
Object* smi_length = len->ToSmi();
if (smi_length->IsSmi()) {
}
break;
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ // TODO(kbr): Add testcase.
+ ExternalArray* array = ExternalArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ return true;
+ }
+ break;
+ }
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
PixelArray* pixels = PixelArray::cast(elements());
return (index < static_cast<uint32_t>(pixels->length()));
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ ExternalArray* array = ExternalArray::cast(elements());
+ return (index < static_cast<uint32_t>(array->length()));
+ }
case DICTIONARY_ELEMENTS: {
return element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound;
}
break;
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ ExternalArray* array = ExternalArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ return true;
+ }
+ break;
+ }
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
PixelArray* pixels = PixelArray::cast(elements());
return pixels->SetValue(index, value);
}
+ case EXTERNAL_BYTE_ELEMENTS: {
+ ExternalByteArray* array = ExternalByteArray::cast(elements());
+ return array->SetValue(index, value);
+ }
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ ExternalUnsignedByteArray* array =
+ ExternalUnsignedByteArray::cast(elements());
+ return array->SetValue(index, value);
+ }
+ case EXTERNAL_SHORT_ELEMENTS: {
+ ExternalShortArray* array = ExternalShortArray::cast(elements());
+ return array->SetValue(index, value);
+ }
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ ExternalUnsignedShortArray* array =
+ ExternalUnsignedShortArray::cast(elements());
+ return array->SetValue(index, value);
+ }
+ case EXTERNAL_INT_ELEMENTS: {
+ ExternalIntArray* array = ExternalIntArray::cast(elements());
+ return array->SetValue(index, value);
+ }
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ ExternalUnsignedIntArray* array =
+ ExternalUnsignedIntArray::cast(elements());
+ return array->SetValue(index, value);
+ }
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ ExternalFloatArray* array = ExternalFloatArray::cast(elements());
+ return array->SetValue(index, value);
+ }
case DICTIONARY_ELEMENTS: {
// Insert element in the dictionary.
FixedArray* elms = FixedArray::cast(elements());
UNIMPLEMENTED();
break;
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ // TODO(kbr): Add testcase and implement.
+ UNIMPLEMENTED();
+ break;
+ }
case DICTIONARY_ELEMENTS: {
NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindEntry(index);
}
break;
}
+ case EXTERNAL_BYTE_ELEMENTS: {
+ ExternalByteArray* array = ExternalByteArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ int8_t value = array->get(index);
+ return Smi::FromInt(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ ExternalUnsignedByteArray* array =
+ ExternalUnsignedByteArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ uint8_t value = array->get(index);
+ return Smi::FromInt(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ case EXTERNAL_SHORT_ELEMENTS: {
+ ExternalShortArray* array = ExternalShortArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ int16_t value = array->get(index);
+ return Smi::FromInt(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ ExternalUnsignedShortArray* array =
+ ExternalUnsignedShortArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ uint16_t value = array->get(index);
+ return Smi::FromInt(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ case EXTERNAL_INT_ELEMENTS: {
+ ExternalIntArray* array = ExternalIntArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ int32_t value = array->get(index);
+ return Heap::NumberFromInt32(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ ExternalUnsignedIntArray* array =
+ ExternalUnsignedIntArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ uint32_t value = array->get(index);
+ return Heap::NumberFromUint32(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ ExternalFloatArray* array = ExternalFloatArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ float value = array->get(index);
+ return Heap::AllocateHeapNumber(value);
+ }
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
case DICTIONARY_ELEMENTS: {
NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindEntry(index);
}
break;
}
- case PIXEL_ELEMENTS: {
+ case PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
return true;
}
case DICTIONARY_ELEMENTS: {
PixelArray* pixels = PixelArray::cast(elements());
return index < static_cast<uint32_t>(pixels->length());
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ ExternalArray* array = ExternalArray::cast(elements());
+ return index < static_cast<uint32_t>(array->length());
+ }
case DICTIONARY_ELEMENTS: {
return element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound;
ASSERT(!storage || storage->length() >= counter);
break;
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS: {
+ int length = ExternalArray::cast(elements())->length();
+ while (counter < length) {
+ if (storage != NULL) {
+ storage->set(counter, Smi::FromInt(counter), SKIP_WRITE_BARRIER);
+ }
+ counter++;
+ }
+ ASSERT(!storage || storage->length() >= counter);
+ break;
+ }
case DICTIONARY_ELEMENTS: {
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage, filter);
// If the object is in dictionary mode, it is converted to fast elements
// mode.
Object* JSObject::PrepareElementsForSort(uint32_t limit) {
- ASSERT(!HasPixelElements());
+ ASSERT(!HasPixelElements() && !HasExternalArrayElements());
if (HasDictionaryElements()) {
// Convert to fast elements containing only the existing properties.
}
+template<typename ExternalArrayClass, typename ValueType>
+static Object* ExternalArrayIntSetter(ExternalArrayClass* receiver,
+ uint32_t index,
+ Object* value) {
+ ValueType cast_value = 0;
+ if (index < static_cast<uint32_t>(receiver->length())) {
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ cast_value = static_cast<ValueType>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ cast_value = static_cast<ValueType>(double_value);
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ ASSERT(value->IsUndefined());
+ }
+ receiver->set(index, cast_value);
+ } else {
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ return Heap::NumberFromInt32(cast_value);
+}
+
+
+Object* ExternalByteArray::SetValue(uint32_t index, Object* value) {
+ return ExternalArrayIntSetter<ExternalByteArray, int8_t>
+ (this, index, value);
+}
+
+
+Object* ExternalUnsignedByteArray::SetValue(uint32_t index, Object* value) {
+ return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
+ (this, index, value);
+}
+
+
+Object* ExternalShortArray::SetValue(uint32_t index, Object* value) {
+ return ExternalArrayIntSetter<ExternalShortArray, int16_t>
+ (this, index, value);
+}
+
+
+Object* ExternalUnsignedShortArray::SetValue(uint32_t index, Object* value) {
+ return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
+ (this, index, value);
+}
+
+
+Object* ExternalIntArray::SetValue(uint32_t index, Object* value) {
+ return ExternalArrayIntSetter<ExternalIntArray, int32_t>
+ (this, index, value);
+}
+
+
+Object* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
+ uint32_t cast_value = 0;
+ if (index < static_cast<uint32_t>(length())) {
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ cast_value = static_cast<uint32_t>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ cast_value = static_cast<uint32_t>(double_value);
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ ASSERT(value->IsUndefined());
+ }
+ set(index, cast_value);
+ } else {
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ return Heap::NumberFromUint32(cast_value);
+}
+
+
+Object* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
+ float cast_value = 0;
+ if (index < static_cast<uint32_t>(length())) {
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ cast_value = static_cast<float>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double double_value = HeapNumber::cast(value)->value();
+ cast_value = static_cast<float>(double_value);
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ ASSERT(value->IsUndefined());
+ }
+ set(index, cast_value);
+ } else {
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ return Heap::AllocateHeapNumber(cast_value);
+}
+
+
Object* GlobalObject::GetPropertyCell(LookupResult* result) {
ASSERT(!HasFastProperties());
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
// - Array
// - ByteArray
// - PixelArray
+// - ExternalArray
+// - ExternalByteArray
+// - ExternalUnsignedByteArray
+// - ExternalShortArray
+// - ExternalUnsignedShortArray
+// - ExternalIntArray
+// - ExternalUnsignedIntArray
+// - ExternalFloatArray
// - FixedArray
// - DescriptorArray
// - HashTable
V(PROXY_TYPE) \
V(BYTE_ARRAY_TYPE) \
V(PIXEL_ARRAY_TYPE) \
+ /* Note: the order of these external array */ \
+ /* types is relied upon in */ \
+ /* Object::IsExternalArray(). */ \
+ V(EXTERNAL_BYTE_ARRAY_TYPE) \
+ V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE) \
+ V(EXTERNAL_SHORT_ARRAY_TYPE) \
+ V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE) \
+ V(EXTERNAL_INT_ARRAY_TYPE) \
+ V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \
+ V(EXTERNAL_FLOAT_ARRAY_TYPE) \
V(FILLER_TYPE) \
\
V(ACCESSOR_INFO_TYPE) \
PROXY_TYPE,
BYTE_ARRAY_TYPE,
PIXEL_ARRAY_TYPE,
+ EXTERNAL_BYTE_ARRAY_TYPE,
+ EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
+ EXTERNAL_SHORT_ARRAY_TYPE,
+ EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
+ EXTERNAL_INT_ARRAY_TYPE,
+ EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
+ EXTERNAL_FLOAT_ARRAY_TYPE,
FILLER_TYPE,
SMI_TYPE,
inline bool IsNumber();
inline bool IsByteArray();
inline bool IsPixelArray();
+ inline bool IsExternalArray();
+ inline bool IsExternalByteArray();
+ inline bool IsExternalUnsignedByteArray();
+ inline bool IsExternalShortArray();
+ inline bool IsExternalUnsignedShortArray();
+ inline bool IsExternalIntArray();
+ inline bool IsExternalUnsignedIntArray();
+ inline bool IsExternalFloatArray();
inline bool IsFailure();
inline bool IsRetryAfterGC();
inline bool IsOutOfMemoryFailure();
enum ElementsKind {
FAST_ELEMENTS,
DICTIONARY_ELEMENTS,
- PIXEL_ELEMENTS
+ PIXEL_ELEMENTS,
+ EXTERNAL_BYTE_ELEMENTS,
+ EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
+ EXTERNAL_SHORT_ELEMENTS,
+ EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
+ EXTERNAL_INT_ELEMENTS,
+ EXTERNAL_UNSIGNED_INT_ELEMENTS,
+ EXTERNAL_FLOAT_ELEMENTS
};
// [properties]: Backing storage for properties.
inline bool HasFastElements();
inline bool HasDictionaryElements();
inline bool HasPixelElements();
+ inline bool HasExternalArrayElements();
+ inline bool HasExternalByteElements();
+ inline bool HasExternalUnsignedByteElements();
+ inline bool HasExternalShortElements();
+ inline bool HasExternalUnsignedShortElements();
+ inline bool HasExternalIntElements();
+ inline bool HasExternalUnsignedIntElements();
+ inline bool HasExternalFloatElements();
inline NumberDictionary* element_dictionary(); // Gets slow elements.
// Collects elements starting at index 0.
};
+// An ExternalArray represents a fixed-size array of primitive values
+// which live outside the JavaScript heap. Its subclasses are used to
+// implement the CanvasArray types being defined in the WebGL
+// specification. As of this writing the first public draft is not yet
+// available, but Khronos members can access the draft at:
+// https://cvs.khronos.org/svn/repos/3dweb/trunk/doc/spec/WebGL-spec.html
+//
+// The semantics of these arrays differ from CanvasPixelArray.
+// Out-of-range values passed to the setter are converted via a C
+// cast, not clamping. Out-of-range indices cause exceptions to be
+// raised rather than being silently ignored.
+class ExternalArray: public Array {
+ public:
+ // [external_pointer]: The pointer to the external memory area backing this
+ // external array.
+ DECL_ACCESSORS(external_pointer, void) // Pointer to the data store.
+
+ // Casting.
+ static inline ExternalArray* cast(Object* obj);
+
+ // Maximal acceptable length for an external array.
+ static const int kMaxLength = 0x3fffffff;
+
+ // ExternalArray headers are not quadword aligned.
+ static const int kExternalPointerOffset = Array::kAlignedSize;
+ static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
+ static const int kAlignedSize = OBJECT_SIZE_ALIGN(kHeaderSize);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalArray);
+};
+
+
+class ExternalByteArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline int8_t get(int index);
+ inline void set(int index, int8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalByteArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalByteArrayPrint();
+ void ExternalByteArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalByteArray);
+};
+
+
+class ExternalUnsignedByteArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline uint8_t get(int index);
+ inline void set(int index, uint8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalUnsignedByteArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalUnsignedByteArrayPrint();
+ void ExternalUnsignedByteArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedByteArray);
+};
+
+
+class ExternalShortArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline int16_t get(int index);
+ inline void set(int index, int16_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalShortArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalShortArrayPrint();
+ void ExternalShortArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalShortArray);
+};
+
+
+class ExternalUnsignedShortArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline uint16_t get(int index);
+ inline void set(int index, uint16_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalUnsignedShortArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalUnsignedShortArrayPrint();
+ void ExternalUnsignedShortArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedShortArray);
+};
+
+
+class ExternalIntArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline int32_t get(int index);
+ inline void set(int index, int32_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalIntArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalIntArrayPrint();
+ void ExternalIntArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalIntArray);
+};
+
+
+class ExternalUnsignedIntArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline uint32_t get(int index);
+ inline void set(int index, uint32_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalUnsignedIntArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalUnsignedIntArrayPrint();
+ void ExternalUnsignedIntArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedIntArray);
+};
+
+
+class ExternalFloatArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline float get(int index);
+ inline void set(int index, float value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalFloatArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void ExternalFloatArrayPrint();
+ void ExternalFloatArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloatArray);
+};
+
+
// Code describes objects with on-the-fly generated machine code.
class Code: public HeapObject {
public:
// Deep copy local elements.
// Pixel elements cannot be created using an object literal.
- ASSERT(!copy->HasPixelElements());
+ ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
case JSObject::FAST_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
return GetElementOrCharAt(object, index);
}
+ // If the target object is a JSObject and has an ExternalArray as
+ // its elements, we need to check for negative indices and report
+ // exceptions. Indices larger than the array's length will be caught
+ // elsewhere.
+ if (key->IsSmi() && Smi::cast(*key)->value() < 0) {
+ if (object->IsJSObject() &&
+ JSObject::cast(*object)->HasExternalArrayElements()) {
+ uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ }
+
// Convert the key to a string - possibly by calling back into JavaScript.
Handle<String> name;
if (key->IsString()) {
return *value;
}
+ // If the target object is a JSObject and has an ExternalArray as
+ // its elements, we need to check for negative indices and report
+ // exceptions. Indices larger than the array's length will be caught
+ // elsewhere.
+ if (key->IsSmi() && Smi::cast(*key)->value() < 0) {
+ if (object->IsJSObject() &&
+ JSObject::cast(*object)->HasExternalArrayElements()) {
+ uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
+ return Top::Throw(*Factory::NewIndexError(index));
+ }
+ }
+
if (key->IsString()) {
Handle<Object> result;
if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
};
+template<class ExternalArrayClass, class ElementType>
+static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
+ bool elements_are_ints,
+ bool elements_are_guaranteed_smis,
+ uint32_t range,
+ ArrayConcatVisitor* visitor) {
+ Handle<ExternalArrayClass> array(
+ ExternalArrayClass::cast(receiver->elements()));
+ uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
+
+ if (visitor != NULL) {
+ if (elements_are_ints) {
+ if (elements_are_guaranteed_smis) {
+ for (uint32_t j = 0; j < len; j++) {
+ Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
+ visitor->visit(j, e);
+ }
+ } else {
+ for (uint32_t j = 0; j < len; j++) {
+ int64_t val = static_cast<int64_t>(array->get(j));
+ if (Smi::IsValid(static_cast<intptr_t>(val))) {
+ Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
+ visitor->visit(j, e);
+ } else {
+ Handle<Object> e(
+ Heap::AllocateHeapNumber(static_cast<ElementType>(val)));
+ visitor->visit(j, e);
+ }
+ }
+ }
+ } else {
+ for (uint32_t j = 0; j < len; j++) {
+ Handle<Object> e(Heap::AllocateHeapNumber(array->get(j)));
+ visitor->visit(j, e);
+ }
+ }
+ }
+
+ return len;
+}
+
/**
* A helper function that visits elements of a JSObject. Only elements
* whose index between 0 and range (exclusive) are visited.
}
break;
}
+ case JSObject::EXTERNAL_BYTE_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalByteArray, int8_t>(
+ receiver, true, true, range, visitor);
+ break;
+ }
+ case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
+ receiver, true, true, range, visitor);
+ break;
+ }
+ case JSObject::EXTERNAL_SHORT_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalShortArray, int16_t>(
+ receiver, true, true, range, visitor);
+ break;
+ }
+ case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
+ receiver, true, true, range, visitor);
+ break;
+ }
+ case JSObject::EXTERNAL_INT_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalIntArray, int32_t>(
+ receiver, true, false, range, visitor);
+ break;
+ }
+ case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
+ receiver, true, false, range, visitor);
+ break;
+ }
+ case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
+ num_of_elements =
+ IterateExternalArrayElements<ExternalFloatArray, float>(
+ receiver, false, false, range, visitor);
+ break;
+ }
case JSObject::DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(receiver->element_dictionary());
uint32_t capacity = dict->Capacity();
SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \
SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \
SC(keyed_load_generic_slow, V8.KeyedLoadGenericSlow) \
+ SC(keyed_load_external_array_slow, V8.KeyedLoadExternalArraySlow) \
/* Count how much the monomorphic keyed-load stubs are hit. */ \
SC(keyed_load_function_prototype, V8.KeyedLoadFunctionPrototype) \
SC(keyed_load_string_length, V8.KeyedLoadStringLength) \
emit_operand(src, dst);
}
+void Assembler::movw(const Operand& dst, Register src) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ emit(0x66);
+ emit_optional_rex_32(src, dst);
+ emit(0x89);
+ emit_operand(src, dst);
+}
+
void Assembler::movl(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+void Assembler::movsxbq(Register dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ emit_rex_32(dst, src);
+ emit(0x0F);
+ emit(0xBE);
+ emit_operand(dst, src);
+}
+
+
+void Assembler::movsxwq(Register dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ emit_rex_64(dst, src);
+ emit(0x0F);
+ emit(0xBF);
+ emit_operand(dst, src);
+}
+
+
void Assembler::movsxlq(Register dst, Register src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+void Assembler::movzxwq(Register dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ emit_rex_64(dst, src);
+ emit(0x0F);
+ emit(0xB7);
+ emit_operand(dst, src);
+}
+
+
void Assembler::movzxwl(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
last_pc_ = pc_;
emit_optional_rex_32(adr);
emit(0xDF);
- emit_operand(8, adr);
+ emit_operand(7, adr);
}
void movb(Register dst, Immediate imm);
void movb(const Operand& dst, Register src);
+ // Move the low 16 bits of a 64-bit register value to a 16-bit
+ // memory location.
+ void movw(const Operand& dst, Register src);
+
void movl(Register dst, Register src);
void movl(Register dst, const Operand& src);
void movl(const Operand& dst, Register src);
void movq(Register dst, ExternalReference ext);
void movq(Register dst, Handle<Object> handle, RelocInfo::Mode rmode);
+ void movsxbq(Register dst, const Operand& src);
+ void movsxwq(Register dst, const Operand& src);
void movsxlq(Register dst, Register src);
void movsxlq(Register dst, const Operand& src);
void movzxbq(Register dst, const Operand& src);
void movzxbl(Register dst, const Operand& src);
+ void movzxwq(Register dst, const Operand& src);
void movzxwl(Register dst, const Operand& src);
// New x64 instruction to load from an immediate 64-bit pointer into RAX.
// operands, jumps to the non_float label otherwise.
static void CheckNumberOperands(MacroAssembler* masm,
Label* non_float);
-
- // Allocate a heap number in new space with undefined value.
- // Returns tagged pointer in result, or jumps to need_gc if new space is full.
- static void AllocateHeapNumber(MacroAssembler* masm,
- Label* need_gc,
- Register scratch,
- Register result);
};
// Allocate heap number for result if possible.
Result scratch = allocator()->Allocate();
Result heap_number = allocator()->Allocate();
- FloatingPointHelper::AllocateHeapNumber(masm_,
- call_runtime.entry_label(),
- scratch.reg(),
- heap_number.reg());
+ __ AllocateHeapNumber(heap_number.reg(),
+ scratch.reg(),
+ call_runtime.entry_label());
scratch.Unuse();
// Store the result in the allocated heap number.
if (overwrite_) {
__ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
} else {
- FloatingPointHelper::AllocateHeapNumber(masm, &slow, rbx, rcx);
+ __ AllocateHeapNumber(rcx, rbx, &slow);
// rcx: allocated 'empty' number
__ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx);
__ movq(rax, rcx);
}
-void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
- Label* need_gc,
- Register scratch,
- Register result) {
- // Allocate heap number in new space.
- __ AllocateInNewSpace(HeapNumber::kSize,
- result,
- scratch,
- no_reg,
- need_gc,
- TAG_OBJECT);
-
- // Set the map and tag the result.
- __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex);
- __ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
-}
-
-
void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
Register number) {
Label load_smi, done;
__ JumpIfNotSmi(rax, &skip_allocation);
// Fall through!
case NO_OVERWRITE:
- FloatingPointHelper::AllocateHeapNumber(masm,
- &call_runtime,
- rcx,
- rax);
+ __ AllocateHeapNumber(rax, rcx, &call_runtime);
__ bind(&skip_allocation);
break;
default: UNREACHABLE();
__ JumpIfNotSmi(rax, &skip_allocation);
// Fall through!
case NO_OVERWRITE:
- FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
- rcx, rax);
+ __ AllocateHeapNumber(rax, rcx, &call_runtime);
__ bind(&skip_allocation);
break;
default: UNREACHABLE();
// Slow case: Load name and receiver from stack and jump to runtime.
__ bind(&slow);
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
- KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
+ Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
__ bind(&check_string);
// The key is not a smi.
// Is it a string?
}
+void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ GenerateGeneric(masm);
+}
+
+
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rsp[0] : return address
// rbx: index (as a smi)
__ j(below, &fast);
- // Slow case: Push extra copies of the arguments (3).
+ // Slow case: call runtime.
__ bind(&slow);
- __ pop(rcx);
- __ push(Operand(rsp, 1 * kPointerSize));
- __ push(Operand(rsp, 1 * kPointerSize));
- __ push(rax);
- __ push(rcx);
- // Do tail-call to runtime routine.
- __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
+ Generate(masm, ExternalReference(Runtime::kSetProperty));
// Check whether the elements is a pixel array.
// rax: value
}
+void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ GenerateGeneric(masm);
+}
+
+
void CallIC::Generate(MacroAssembler* masm,
int argc,
ExternalReference const& f) {
}
+Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) {
+ // An unsigned 32-bit integer value is valid as long as the high bit
+ // is not set.
+ testq(src, Immediate(0x80000000));
+ return zero;
+}
+
+
void MacroAssembler::SmiNeg(Register dst, Register src, Label* on_smi_result) {
if (dst.is(src)) {
ASSERT(!dst.is(kScratchRegister));
}
+void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src,
+ Label* on_invalid) {
+ Condition is_valid = CheckUInteger32ValidSmiValue(src);
+ j(NegateCondition(is_valid), on_invalid);
+}
+
+
void MacroAssembler::JumpIfNotBothSmi(Register src1, Register src2,
Label* on_not_both_smi) {
Condition both_smi = CheckBothSmi(src1, src2);
}
+void MacroAssembler::AllocateHeapNumber(Register result,
+ Register scratch,
+ Label* gc_required) {
+ // Allocate heap number in new space.
+ AllocateInNewSpace(HeapNumber::kSize,
+ result,
+ scratch,
+ no_reg,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map.
+ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex);
+ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
+}
+
+
CodePatcher::CodePatcher(byte* address, int size)
: address_(address), size_(size), masm_(address, size + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch.
// to a smi.
Condition CheckInteger32ValidSmiValue(Register src);
+ // Checks whether an 32-bit unsigned integer value is a valid for
+ // conversion to a smi.
+ Condition CheckUInteger32ValidSmiValue(Register src);
+
// Test-and-jump functions. Typically combines a check function
// above with a conditional jump.
// Jump if the value cannot be represented by a smi.
void JumpIfNotValidSmiValue(Register src, Label* on_invalid);
+ // Jump if the unsigned integer value cannot be represented by a smi.
+ void JumpIfUIntNotValidSmiValue(Register src, Label* on_invalid);
+
// Jump to label if the value is a tagged smi.
void JumpIfSmi(Register src, Label* on_smi);
// un-done.
void UndoAllocationInNewSpace(Register object);
+ // Allocate a heap number in new space with undefined value. Returns
+ // tagged pointer in result register, or jumps to gc_required if new
+ // space is full.
+ void AllocateHeapNumber(Register result,
+ Register scratch,
+ Label* gc_required);
+
// ---------------------------------------------------------------------------
// Support functions.
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <limits.h>
+
#include "v8.h"
#include "api.h"
#include "snapshot.h"
#include "platform.h"
#include "top.h"
+#include "utils.h"
#include "cctest.h"
static bool IsNaN(double x) {
}
+template <class ExternalArrayClass, class ElementType>
+static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
+ int64_t low,
+ int64_t high) {
+ v8::HandleScope scope;
+ LocalContext context;
+ const int kElementCount = 40;
+ int element_size = 0;
+ switch (array_type) {
+ case v8::kExternalByteArray:
+ case v8::kExternalUnsignedByteArray:
+ element_size = 1;
+ break;
+ case v8::kExternalShortArray:
+ case v8::kExternalUnsignedShortArray:
+ element_size = 2;
+ break;
+ case v8::kExternalIntArray:
+ case v8::kExternalUnsignedIntArray:
+ case v8::kExternalFloatArray:
+ element_size = 4;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ ElementType* array_data =
+ static_cast<ElementType*>(malloc(kElementCount * element_size));
+ i::Handle<ExternalArrayClass> array =
+ i::Handle<ExternalArrayClass>::cast(
+ i::Factory::NewExternalArray(kElementCount, array_type, array_data));
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ for (int i = 0; i < kElementCount; i++) {
+ array->set(i, static_cast<ElementType>(i));
+ }
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ for (int i = 0; i < kElementCount; i++) {
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
+ }
+
+ v8::Handle<v8::Object> obj = v8::Object::New();
+ i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
+ // Set the elements to be the external array.
+ obj->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+ CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
+ obj->Set(v8_str("field"), v8::Int32::New(1503));
+ context->Global()->Set(v8_str("ext_array"), obj);
+ v8::Handle<v8::Value> result = CompileRun("ext_array.field");
+ CHECK_EQ(1503, result->Int32Value());
+ result = CompileRun("ext_array[1]");
+ CHECK_EQ(1, result->Int32Value());
+
+ // Check pass through of assigned smis
+ result = CompileRun("var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += ext_array[i] = ext_array[i] = -i;"
+ "}"
+ "sum;");
+ CHECK_EQ(-28, result->Int32Value());
+
+ // Check assigned smis
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = i;"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check assigned smis in reverse order
+ result = CompileRun("for (var i = 8; --i >= 0; ) {"
+ " ext_array[i] = i;"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check pass through of assigned HeapNumbers
+ result = CompileRun("var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
+ "}"
+ "sum;");
+ CHECK_EQ(-28, result->Int32Value());
+
+ // Check assigned HeapNumbers
+ result = CompileRun("for (var i = 0; i < 16; i+=2) {"
+ " ext_array[i] = (i * 0.5);"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check assigned HeapNumbers in reverse order
+ result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
+ " ext_array[i] = (i * 0.5);"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ i::ScopedVector<char> test_buf(1024);
+
+ // Check legal boundary conditions.
+ // The repeated loads and stores ensure the ICs are exercised.
+ const char* boundary_program =
+ "var res = 0;"
+ "for (var i = 0; i < 16; i++) {"
+ " ext_array[i] = %lld;"
+ " if (i > 8) {"
+ " res = ext_array[i];"
+ " }"
+ "}"
+ "res;";
+ i::OS::SNPrintF(test_buf,
+ boundary_program,
+ low);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(low, result->IntegerValue());
+
+ i::OS::SNPrintF(test_buf,
+ boundary_program,
+ high);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(high, result->IntegerValue());
+
+ // Check misprediction of type in IC.
+ result = CompileRun("var tmp_array = ext_array;"
+ "var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " tmp_array[i] = i;"
+ " sum += tmp_array[i];"
+ " if (i == 4) {"
+ " tmp_array = {};"
+ " }"
+ "}"
+ "sum;");
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check out-of-range loads.
+ result = CompileRun("var caught_exception = false;"
+ "try {"
+ " ext_array[-1];"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;");
+ CHECK_EQ(true, result->BooleanValue());
+
+ i::OS::SNPrintF(test_buf,
+ "var caught_exception = false;"
+ "try {"
+ " ext_array[%d];"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;",
+ kElementCount);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(true, result->BooleanValue());
+
+ // Check out-of-range stores.
+ result = CompileRun("var caught_exception = false;"
+ "try {"
+ " ext_array[-1] = 1;"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;");
+ CHECK_EQ(true, result->BooleanValue());
+
+ i::OS::SNPrintF(test_buf,
+ "var caught_exception = false;"
+ "try {"
+ " ext_array[%d] = 1;"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;",
+ kElementCount);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(true, result->BooleanValue());
+
+ // TODO(kbr): check what happens during IC misses on the type of the object.
+ // Re-assign array object halfway through a loop.
+
+ // Check other boundary conditions, values and operations.
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[7] = undefined;"
+ "}"
+ "ext_array[7];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[6] = '2.3';"
+ "}"
+ "ext_array[6];");
+ CHECK_EQ(2, result->Int32Value());
+ CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
+
+ // Result for storing NaNs and +/-Infinity isn't defined for these
+ // types; they do not have the clamping behavior CanvasPixelArray
+ // specifies.
+
+ result = CompileRun("ext_array[3] = 33;"
+ "delete ext_array[3];"
+ "ext_array[3];");
+ CHECK_EQ(33, result->Int32Value());
+
+ result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
+ "ext_array[2] = 12; ext_array[3] = 13;"
+ "ext_array.__defineGetter__('2',"
+ "function() { return 120; });"
+ "ext_array[2];");
+ CHECK_EQ(12, result->Int32Value());
+
+ result = CompileRun("var js_array = new Array(40);"
+ "js_array[0] = 77;"
+ "js_array;");
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+
+ result = CompileRun("ext_array[1] = 23;"
+ "ext_array.__proto__ = [];"
+ "js_array.__proto__ = ext_array;"
+ "js_array.concat(ext_array);");
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+ CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
+
+ result = CompileRun("ext_array[1] = 23;");
+ CHECK_EQ(23, result->Int32Value());
+
+ free(array_data);
+}
+
+
+THREADED_TEST(ExternalByteArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
+ v8::kExternalByteArray,
+ -128,
+ 127);
+}
+
+
+THREADED_TEST(ExternalUnsignedByteArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
+ v8::kExternalUnsignedByteArray,
+ 0,
+ 255);
+}
+
+
+THREADED_TEST(ExternalShortArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
+ v8::kExternalShortArray,
+ -32768,
+ 32767);
+}
+
+
+THREADED_TEST(ExternalUnsignedShortArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
+ v8::kExternalUnsignedShortArray,
+ 0,
+ 65535);
+}
+
+
+THREADED_TEST(ExternalIntArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
+ v8::kExternalIntArray,
+ INT_MIN, // -2147483648
+ INT_MAX); // 2147483647
+}
+
+
+THREADED_TEST(ExternalUnsignedIntArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
+ v8::kExternalUnsignedIntArray,
+ 0,
+ UINT_MAX); // 4294967295
+}
+
+
+THREADED_TEST(ExternalFloatArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
+ v8::kExternalFloatArray,
+ -500,
+ 500);
+}
+
+
+THREADED_TEST(ExternalArrays) {
+ TestExternalByteArray();
+ TestExternalUnsignedByteArray();
+ TestExternalShortArray();
+ TestExternalUnsignedShortArray();
+ TestExternalIntArray();
+ TestExternalUnsignedIntArray();
+ TestExternalFloatArray();
+}
+
+
THREADED_TEST(ScriptContextDependence) {
v8::HandleScope scope;
LocalContext c1;