Version 3.3.9.
Added DateTimeFormat class to experimental i18n API.
Extended preparser to give early errors for some strict mode restrictions.
Removed legacy execScript function from V8.
Extended isolate API with the ability to add embedder-specific data to an isolate.
Added basic support for polymorphic loads from JS and external arrays.
Fixed bug in handling of switch statements in the optimizing compiler.
git-svn-id: http://v8.googlecode.com/svn/trunk@7972 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 30e0881..5980854 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -936,9 +936,9 @@
}
-#define SET_FIELD_WRAPPED(obj, setter, cdata) do { \
- i::Handle<i::Object> proxy = FromCData(cdata); \
- (obj)->setter(*proxy); \
+#define SET_FIELD_WRAPPED(obj, setter, cdata) do { \
+ i::Handle<i::Object> foreign = FromCData(cdata); \
+ (obj)->setter(*foreign); \
} while (false)
@@ -2058,7 +2058,7 @@
if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsExternal()")) {
return false;
}
- return Utils::OpenHandle(this)->IsProxy();
+ return Utils::OpenHandle(this)->IsForeign();
}
@@ -2219,7 +2219,7 @@
void External::CheckCast(v8::Value* that) {
if (IsDeadCheck(i::Isolate::Current(), "v8::External::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->IsProxy(),
+ ApiCheck(obj->IsForeign(),
"v8::External::Cast()",
"Could not convert to external");
}
@@ -3729,11 +3729,11 @@
Utils::OpenHandle(this)->SetInternalField(index, EncodeAsSmi(value));
} else {
HandleScope scope;
- i::Handle<i::Proxy> proxy =
- isolate->factory()->NewProxy(
+ i::Handle<i::Foreign> foreign =
+ isolate->factory()->NewForeign(
reinterpret_cast<i::Address>(value), i::TENURED);
- if (!proxy.is_null())
- Utils::OpenHandle(this)->SetInternalField(index, *proxy);
+ if (!foreign.is_null())
+ Utils::OpenHandle(this)->SetInternalField(index, *foreign);
}
ASSERT_EQ(value, GetPointerFromInternalField(index));
}
@@ -4069,11 +4069,11 @@
static Local<External> ExternalNewImpl(void* data) {
- return Utils::ToLocal(FACTORY->NewProxy(static_cast<i::Address>(data)));
+ return Utils::ToLocal(FACTORY->NewForeign(static_cast<i::Address>(data)));
}
static void* ExternalValueImpl(i::Handle<i::Object> obj) {
- return reinterpret_cast<void*>(i::Proxy::cast(*obj)->proxy());
+ return reinterpret_cast<void*>(i::Foreign::cast(*obj)->address());
}
@@ -4098,8 +4098,8 @@
i::Object* value = obj->GetInternalField(index);
if (value->IsSmi()) {
return i::Internals::GetExternalPointerFromSmi(value);
- } else if (value->IsProxy()) {
- return reinterpret_cast<void*>(i::Proxy::cast(value)->proxy());
+ } else if (value->IsForeign()) {
+ return reinterpret_cast<void*>(i::Foreign::cast(value)->address());
} else {
return NULL;
}
@@ -4112,7 +4112,7 @@
void* result;
if (obj->IsSmi()) {
result = i::Internals::GetExternalPointerFromSmi(*obj);
- } else if (obj->IsProxy()) {
+ } else if (obj->IsForeign()) {
result = ExternalValueImpl(obj);
} else {
result = NULL;
@@ -4558,7 +4558,7 @@
i::HandleScope scope(isolate);
NeanderArray listeners(isolate->factory()->message_listeners());
NeanderObject obj(2);
- obj.set(0, *isolate->factory()->NewProxy(FUNCTION_ADDR(that)));
+ obj.set(0, *isolate->factory()->NewForeign(FUNCTION_ADDR(that)));
obj.set(1, data.IsEmpty() ?
isolate->heap()->undefined_value() :
*Utils::OpenHandle(*data));
@@ -4578,8 +4578,8 @@
if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones
NeanderObject listener(i::JSObject::cast(listeners.get(i)));
- i::Handle<i::Proxy> callback_obj(i::Proxy::cast(listener.get(0)));
- if (callback_obj->proxy() == FUNCTION_ADDR(that)) {
+ i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0)));
+ if (callback_obj->address() == FUNCTION_ADDR(that)) {
listeners.set(i, isolate->heap()->undefined_value());
}
}
@@ -4870,6 +4870,17 @@
}
+void Isolate::SetData(void* data) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->SetData(data);
+}
+
+void* Isolate::GetData() {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ return isolate->GetData();
+}
+
+
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj)
: str_(NULL), length_(0) {
i::Isolate* isolate = i::Isolate::Current();
@@ -5038,11 +5049,12 @@
isolate->set_debug_event_callback(that);
i::HandleScope scope(isolate);
- i::Handle<i::Object> proxy = isolate->factory()->undefined_value();
+ i::Handle<i::Object> foreign = isolate->factory()->undefined_value();
if (that != NULL) {
- proxy = isolate->factory()->NewProxy(FUNCTION_ADDR(EventCallbackWrapper));
+ foreign =
+ isolate->factory()->NewForeign(FUNCTION_ADDR(EventCallbackWrapper));
}
- isolate->debugger()->SetEventListener(proxy, Utils::OpenHandle(*data));
+ isolate->debugger()->SetEventListener(foreign, Utils::OpenHandle(*data));
return true;
}
@@ -5053,12 +5065,11 @@
ON_BAILOUT(isolate, "v8::Debug::SetDebugEventListener2()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
- i::Handle<i::Object> proxy = isolate->factory()->undefined_value();
+ i::Handle<i::Object> foreign = isolate->factory()->undefined_value();
if (that != NULL) {
- proxy = isolate->factory()->NewProxy(FUNCTION_ADDR(that));
+ foreign = isolate->factory()->NewForeign(FUNCTION_ADDR(that));
}
- isolate->debugger()->SetEventListener(proxy,
- Utils::OpenHandle(*data));
+ isolate->debugger()->SetEventListener(foreign, Utils::OpenHandle(*data));
return true;
}
diff --git a/src/api.h b/src/api.h
index 90cada7..21f5043 100644
--- a/src/api.h
+++ b/src/api.h
@@ -115,14 +115,14 @@
template <typename T> static inline T ToCData(v8::internal::Object* obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
return reinterpret_cast<T>(
- reinterpret_cast<intptr_t>(v8::internal::Proxy::cast(obj)->proxy()));
+ reinterpret_cast<intptr_t>(v8::internal::Foreign::cast(obj)->address()));
}
template <typename T>
static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
- return FACTORY->NewProxy(
+ return FACTORY->NewForeign(
reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj)));
}
@@ -182,7 +182,7 @@
static inline Local<Array> ToLocal(
v8::internal::Handle<v8::internal::JSArray> obj);
static inline Local<External> ToLocal(
- v8::internal::Handle<v8::internal::Proxy> obj);
+ v8::internal::Handle<v8::internal::Foreign> obj);
static inline Local<Message> MessageToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<StackTrace> StackTraceToLocal(
@@ -236,7 +236,7 @@
OpenHandle(const v8::Signature* sig);
static inline v8::internal::Handle<v8::internal::TypeSwitchInfo>
OpenHandle(const v8::TypeSwitch* that);
- static inline v8::internal::Handle<v8::internal::Proxy>
+ static inline v8::internal::Handle<v8::internal::Foreign>
OpenHandle(const v8::External* that);
};
@@ -273,7 +273,7 @@
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
-MAKE_TO_LOCAL(ToLocal, Proxy, External)
+MAKE_TO_LOCAL(ToLocal, Foreign, External)
MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate)
MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate)
MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature)
@@ -311,7 +311,7 @@
MAKE_OPEN_HANDLE(Function, JSFunction)
MAKE_OPEN_HANDLE(Message, JSObject)
MAKE_OPEN_HANDLE(Context, Context)
-MAKE_OPEN_HANDLE(External, Proxy)
+MAKE_OPEN_HANDLE(External, Foreign)
MAKE_OPEN_HANDLE(StackTrace, JSArray)
MAKE_OPEN_HANDLE(StackFrame, JSObject)
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 8120324..efec81f 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -1616,12 +1616,36 @@
// The stub returns zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
// This stub uses VFP3 instructions.
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ CpuFeatures::Scope scope(VFP3);
Label false_result;
Label not_heap_number;
Register scratch = r9.is(tos_) ? r7 : r9;
+ // undefined -> false
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ cmp(tos_, ip);
+ __ b(eq, &false_result);
+
+ // Boolean -> its value
+ __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+ __ cmp(tos_, ip);
+ __ b(eq, &false_result);
+ __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+ __ cmp(tos_, ip);
+ // "tos_" is a register and contains a non-zero value. Hence we implicitly
+ // return true if the equal condition is satisfied.
+ __ Ret(eq);
+
+ // Smis: 0 -> false, all other -> true
+ __ tst(tos_, tos_);
+ __ b(eq, &false_result);
+ __ tst(tos_, Operand(kSmiTagMask));
+ // "tos_" is a register and contains a non-zero value. Hence we implicitly
+ // return true if the not equal condition is satisfied.
+ __ Ret(eq);
+
+ // 'null' -> false
__ LoadRoot(ip, Heap::kNullValueRootIndex);
__ cmp(tos_, ip);
__ b(eq, &false_result);
@@ -1631,9 +1655,7 @@
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(scratch, ip);
__ b(¬_heap_number, ne);
-
- __ sub(ip, tos_, Operand(kHeapObjectTag));
- __ vldr(d1, ip, HeapNumber::kValueOffset);
+ __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
__ VFPCompareAndSetFlags(d1, 0.0);
// "tos_" is a register, and contains a non zero value by default.
// Hence we only need to overwrite "tos_" with zero to return false for
@@ -1644,12 +1666,6 @@
__ bind(¬_heap_number);
- // Check if the value is 'null'.
- // 'null' => false.
- __ LoadRoot(ip, Heap::kNullValueRootIndex);
- __ cmp(tos_, ip);
- __ b(&false_result, eq);
-
// It can be an undetectable object.
// Undetectable => false.
__ ldr(ip, FieldMemOperand(tos_, HeapObject::kMapOffset));
@@ -1831,12 +1847,14 @@
void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow);
+ Label non_smi, slow, call_builtin;
+ GenerateSmiCodeSub(masm, &non_smi, &call_builtin);
__ bind(&non_smi);
GenerateHeapNumberCodeSub(masm, &slow);
__ bind(&slow);
GenerateTypeTransition(masm);
+ __ bind(&call_builtin);
+ GenerateGenericCodeFallback(masm);
}
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 5bc1355..9cc6be2 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -1,4 +1,4 @@
-// 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:
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 68a2355..2b7cdef 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -562,23 +562,6 @@
Label* if_false,
Label* fall_through) {
if (CpuFeatures::IsSupported(VFP3)) {
- CpuFeatures::Scope scope(VFP3);
- // Emit the inlined tests assumed by the stub.
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ cmp(result_register(), ip);
- __ b(eq, if_false);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ cmp(result_register(), ip);
- __ b(eq, if_true);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ cmp(result_register(), ip);
- __ b(eq, if_false);
- STATIC_ASSERT(kSmiTag == 0);
- __ tst(result_register(), result_register());
- __ b(eq, if_false);
- __ JumpIfSmi(result_register(), if_true);
-
- // Call the ToBoolean stub for all other cases.
ToBooleanStub stub(result_register());
__ CallStub(&stub);
__ tst(result_register(), result_register());
@@ -590,8 +573,6 @@
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ cmp(r0, ip);
}
-
- // The stub returns nonzero for true.
Split(ne, if_true, if_false, fall_through);
}
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 731c471..8749eea 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -868,10 +868,7 @@
}
-Object* KeyedLoadIC_Miss(Arguments args);
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
@@ -883,8 +880,11 @@
__ Push(r1, r0);
- ExternalReference ref =
- ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
+ // Perform tail call to the entry.
+ ExternalReference ref = force_generic
+ ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
+ : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
+
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1075,7 +1075,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
@@ -1115,11 +1115,11 @@
1);
__ bind(&slow);
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
@@ -1130,8 +1130,29 @@
// Push receiver, key and value for runtime call.
__ Push(r2, r1, r0);
+ ExternalReference ref = force_generic
+ ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
+ masm->isolate())
+ : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
+ __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
+ // ---------- S t a t e --------------
+ // -- r0 : value
+ // -- r1 : key
+ // -- r2 : receiver
+ // -- lr : return address
+ // -----------------------------------
+
+ // Push receiver, key and value for runtime call.
+ __ Push(r2, r1, r0);
+
+ // The slow case calls into the runtime to complete the store without causing
+ // an IC miss that would otherwise cause a transition to the generic stub.
ExternalReference ref =
- ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
+ ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index e9e8351..32b0454 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1050,107 +1050,97 @@
LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HValue* v = instr->value();
- if (v->EmitAtUses()) {
- if (v->IsClassOfTest()) {
- HClassOfTest* compare = HClassOfTest::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
- TempRegister());
- } else if (v->IsCompare()) {
- HCompare* compare = HCompare::cast(v);
- Token::Value op = compare->token();
- HValue* left = compare->left();
- HValue* right = compare->right();
- Representation r = compare->GetInputRepresentation();
- if (r.IsInteger32()) {
- ASSERT(left->representation().IsInteger32());
- ASSERT(right->representation().IsInteger32());
- return new LCmpIDAndBranch(UseRegisterAtStart(left),
- UseRegisterAtStart(right));
- } else if (r.IsDouble()) {
- ASSERT(left->representation().IsDouble());
- ASSERT(right->representation().IsDouble());
- return new LCmpIDAndBranch(UseRegisterAtStart(left),
- UseRegisterAtStart(right));
- } else {
- ASSERT(left->representation().IsTagged());
- ASSERT(right->representation().IsTagged());
- bool reversed = op == Token::GT || op == Token::LTE;
- LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
- LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
- LInstruction* result = new LCmpTAndBranch(left_operand,
- right_operand);
- return MarkAsCall(result, instr);
- }
- } else if (v->IsIsSmi()) {
- HIsSmi* compare = HIsSmi::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsSmiAndBranch(Use(compare->value()));
- } else if (v->IsIsUndetectable()) {
- HIsUndetectable* compare = HIsUndetectable::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
- TempRegister());
- } else if (v->IsHasInstanceType()) {
- HHasInstanceType* compare = HHasInstanceType::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
- return new LHasInstanceTypeAndBranch(
- UseRegisterAtStart(compare->value()));
- } else if (v->IsHasCachedArrayIndex()) {
- HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LHasCachedArrayIndexAndBranch(
- UseRegisterAtStart(compare->value()));
- } else if (v->IsIsNull()) {
- HIsNull* compare = HIsNull::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsNullAndBranch(UseRegisterAtStart(compare->value()));
- } else if (v->IsIsObject()) {
- HIsObject* compare = HIsObject::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- LOperand* temp = TempRegister();
- return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp);
- } else if (v->IsCompareJSObjectEq()) {
- HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
- return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
- UseRegisterAtStart(compare->right()));
- } else if (v->IsCompareSymbolEq()) {
- HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
- return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
- UseRegisterAtStart(compare->right()));
- } else if (v->IsInstanceOf()) {
- HInstanceOf* instance_of = HInstanceOf::cast(v);
- LInstruction* result =
- new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0),
- UseFixed(instance_of->right(), r1));
- return MarkAsCall(result, instr);
- } else if (v->IsTypeofIs()) {
- HTypeofIs* typeof_is = HTypeofIs::cast(v);
- return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
- } else if (v->IsIsConstructCall()) {
- return new LIsConstructCallAndBranch(TempRegister());
+ if (!v->EmitAtUses()) {
+ return new LBranch(UseRegisterAtStart(v));
+ } else if (v->IsClassOfTest()) {
+ HClassOfTest* compare = HClassOfTest::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
+ TempRegister());
+ } else if (v->IsCompare()) {
+ HCompare* compare = HCompare::cast(v);
+ Token::Value op = compare->token();
+ HValue* left = compare->left();
+ HValue* right = compare->right();
+ Representation r = compare->GetInputRepresentation();
+ if (r.IsInteger32()) {
+ ASSERT(left->representation().IsInteger32());
+ ASSERT(right->representation().IsInteger32());
+ return new LCmpIDAndBranch(UseRegisterAtStart(left),
+ UseRegisterAtStart(right));
+ } else if (r.IsDouble()) {
+ ASSERT(left->representation().IsDouble());
+ ASSERT(right->representation().IsDouble());
+ return new LCmpIDAndBranch(UseRegisterAtStart(left),
+ UseRegisterAtStart(right));
} else {
- if (v->IsConstant()) {
- if (HConstant::cast(v)->ToBoolean()) {
- return new LGoto(instr->FirstSuccessor()->block_id());
- } else {
- return new LGoto(instr->SecondSuccessor()->block_id());
- }
- }
- Abort("Undefined compare before branch");
- return NULL;
+ ASSERT(left->representation().IsTagged());
+ ASSERT(right->representation().IsTagged());
+ bool reversed = op == Token::GT || op == Token::LTE;
+ LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
+ LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
+ LInstruction* result = new LCmpTAndBranch(left_operand, right_operand);
+ return MarkAsCall(result, instr);
}
+ } else if (v->IsIsSmi()) {
+ HIsSmi* compare = HIsSmi::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsSmiAndBranch(Use(compare->value()));
+ } else if (v->IsIsUndetectable()) {
+ HIsUndetectable* compare = HIsUndetectable::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
+ TempRegister());
+ } else if (v->IsHasInstanceType()) {
+ HHasInstanceType* compare = HHasInstanceType::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()));
+ } else if (v->IsHasCachedArrayIndex()) {
+ HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LHasCachedArrayIndexAndBranch(
+ UseRegisterAtStart(compare->value()));
+ } else if (v->IsIsNull()) {
+ HIsNull* compare = HIsNull::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsNullAndBranch(UseRegisterAtStart(compare->value()));
+ } else if (v->IsIsObject()) {
+ HIsObject* compare = HIsObject::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ LOperand* temp = TempRegister();
+ return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp);
+ } else if (v->IsCompareJSObjectEq()) {
+ HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
+ return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
+ UseRegisterAtStart(compare->right()));
+ } else if (v->IsCompareSymbolEq()) {
+ HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
+ return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
+ UseRegisterAtStart(compare->right()));
+ } else if (v->IsInstanceOf()) {
+ HInstanceOf* instance_of = HInstanceOf::cast(v);
+ LInstruction* result =
+ new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0),
+ UseFixed(instance_of->right(), r1));
+ return MarkAsCall(result, instr);
+ } else if (v->IsTypeofIs()) {
+ HTypeofIs* typeof_is = HTypeofIs::cast(v);
+ return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+ } else if (v->IsIsConstructCall()) {
+ return new LIsConstructCallAndBranch(TempRegister());
+ } else if (v->IsConstant()) {
+ HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
+ ? instr->FirstSuccessor()
+ : instr->SecondSuccessor();
+ return new LGoto(successor->block_id());
+ } else {
+ Abort("Undefined compare before branch");
+ return NULL;
}
- return new LBranch(UseRegisterAtStart(v));
}
+
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 340ac37..885dd5a 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -1681,6 +1681,23 @@
}
+void MacroAssembler::DispatchMap(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type) {
+ Label fail;
+ if (smi_check_type == DO_SMI_CHECK) {
+ JumpIfSmi(obj, &fail);
+ }
+ ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+ mov(ip, Operand(map));
+ cmp(scratch, ip);
+ Jump(success, RelocInfo::CODE_TARGET, eq);
+ bind(&fail);
+}
+
+
void MacroAssembler::TryGetFunctionPrototype(Register function,
Register result,
Register scratch,
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 9be4ca0..8996537 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -578,6 +578,7 @@
Label* fail,
SmiCheckType smi_check_type);
+
void CheckMap(Register obj,
Register scratch,
Heap::RootListIndex index,
@@ -585,6 +586,16 @@
SmiCheckType smi_check_type);
+ // Check if the map of an object is equal to a specified map and branch to a
+ // specified target if equal. Skip the smi check if not required (object is
+ // known to be a heap object)
+ void DispatchMap(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type);
+
+
// Compare the object in a register to a value from the root list.
// Uses the ip register as scratch.
void CompareRoot(Register obj, Heap::RootListIndex index);
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index eca3e45..db68193 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -2262,6 +2262,7 @@
// repatch it to global receiver.
if (object->IsGlobalObject()) return heap()->undefined_value();
if (cell != NULL) return heap()->undefined_value();
+ if (!object->IsJSObject()) return heap()->undefined_value();
int depth = optimization.GetPrototypeDepthOfExpectedType(
JSObject::cast(object), holder);
if (depth == kInvalidProtoDepth) return heap()->undefined_value();
@@ -3091,52 +3092,56 @@
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- r0 : key
+ // -- r1 : receiver
+ // -----------------------------------
+ MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(r1,
+ r2,
+ Handle<Map>(receiver_map),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Label miss;
+ __ JumpIfSmi(r1, &miss);
- // Check that the receiver isn't a smi.
- __ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the map matches.
+ int receiver_count = receiver_maps->length();
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ cmp(r2, Operand(Handle<Map>(receiver->map())));
- __ b(ne, &miss);
-
- // Check that the key is a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(ne, &miss);
-
- // Get the elements array.
- __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
- __ AssertFastElements(r2);
-
- // Check that the key is within bounds.
- __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
- __ cmp(r0, Operand(r3));
- __ b(hs, &miss);
-
- // Load the result and make sure it's not the hole.
- __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
- __ ldr(r4,
- MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r4, ip);
- __ b(eq, &miss);
- __ mov(r0, r4);
- __ Ret();
+ for (int current = 0; current < receiver_count; ++current) {
+ Handle<Map> map(receiver_maps->at(current));
+ Handle<Code> code(handler_ics->at(current));
+ __ mov(ip, Operand(map));
+ __ cmp(r2, ip);
+ __ Jump(code, RelocInfo::CODE_TARGET, eq);
+ }
__ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+ Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
+ __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@@ -3178,69 +3183,27 @@
}
-MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
- JSObject* receiver) {
+MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement(
+ Map* receiver_map) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : scratch
- // -- r4 : scratch (elements)
// -----------------------------------
- Label miss;
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ MaybeObject* maybe_stub =
+ KeyedStoreFastElementStub(is_js_array).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(r2,
+ r3,
+ Handle<Map>(receiver_map),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
- Register value_reg = r0;
- Register key_reg = r1;
- Register receiver_reg = r2;
- Register scratch = r3;
- Register elements_reg = r4;
-
- // Check that the receiver isn't a smi.
- __ tst(receiver_reg, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the map matches.
- __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
- __ cmp(scratch, Operand(Handle<Map>(receiver->map())));
- __ b(ne, &miss);
-
- // Check that the key is a smi.
- __ tst(key_reg, Operand(kSmiTagMask));
- __ b(ne, &miss);
-
- // Get the elements array and make sure it is a fast element array, not 'cow'.
- __ ldr(elements_reg,
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
- __ ldr(scratch, FieldMemOperand(elements_reg, HeapObject::kMapOffset));
- __ cmp(scratch, Operand(Handle<Map>(factory()->fixed_array_map())));
- __ b(ne, &miss);
-
- // Check that the key is within bounds.
- if (receiver->IsJSArray()) {
- __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
- } else {
- __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
- }
- // Compare smis.
- __ cmp(key_reg, scratch);
- __ b(hs, &miss);
-
- __ add(scratch,
- elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
- __ str(value_reg,
- MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ RecordWrite(scratch,
- Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize),
- receiver_reg , elements_reg);
-
- // value_reg (r0) is preserved.
- // Done.
- __ Ret();
-
- __ bind(&miss);
- Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -3248,6 +3211,38 @@
}
+MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics) {
+ // ----------- S t a t e -------------
+ // -- r0 : value
+ // -- r1 : key
+ // -- r2 : receiver
+ // -- lr : return address
+ // -- r3 : scratch
+ // -----------------------------------
+ Label miss;
+ __ JumpIfSmi(r2, &miss);
+
+ int receiver_count = receiver_maps->length();
+ __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
+ for (int current = 0; current < receiver_count; ++current) {
+ Handle<Map> map(receiver_maps->at(current));
+ Handle<Code> code(handler_ics->at(current));
+ __ mov(ip, Operand(map));
+ __ cmp(r3, ip);
+ __ Jump(code, RelocInfo::CODE_TARGET, eq);
+ }
+
+ __ bind(&miss);
+ Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL, MEGAMORPHIC);
+}
+
+
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// ----------- S t a t e -------------
// -- r0 : argc
@@ -3392,6 +3387,60 @@
}
+MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad(
+ JSObject*receiver, ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- r0 : key
+ // -- r1 : receiver
+ // -----------------------------------
+ MaybeObject* maybe_stub =
+ KeyedLoadExternalArrayStub(array_type).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(r1,
+ r2,
+ Handle<Map>(receiver->map()),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode();
+}
+
+
+MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
+ JSObject* receiver, ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- r0 : value
+ // -- r1 : name
+ // -- r2 : receiver
+ // -- lr : return address
+ // -----------------------------------
+ MaybeObject* maybe_stub =
+ KeyedStoreExternalArrayStub(array_type).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(r2,
+ r3,
+ Handle<Map>(receiver->map()),
+ Handle<Code>(stub),
+ DONT_DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ return GetCode();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
static bool IsElementTypeSigned(ExternalArrayType array_type) {
switch (array_type) {
case kExternalByteArray:
@@ -3411,30 +3460,24 @@
}
-MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- JSObject* receiver_object,
- ExternalArrayType array_type,
- Code::Flags flags) {
+void KeyedLoadStubCompiler::GenerateLoadExternalArray(
+ MacroAssembler* masm,
+ ExternalArrayType array_type) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
- Label slow, failed_allocation;
+ Label miss_force_generic, slow, failed_allocation;
Register key = r0;
Register receiver = r1;
- // Check that the object isn't a smi
- __ JumpIfSmi(receiver, &slow);
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
// Check that the key is a smi.
- __ JumpIfNotSmi(key, &slow);
-
- // Make sure that we've got the right map.
- __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ cmp(r2, Operand(Handle<Map>(receiver_object->map())));
- __ b(ne, &slow);
+ __ JumpIfNotSmi(key, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// r3: elements array
@@ -3443,7 +3486,7 @@
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(ip, Operand(key, ASR, kSmiTagSize));
// Unsigned comparison catches both negative and too-large values.
- __ b(lo, &slow);
+ __ b(lo, &miss_force_generic);
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage
@@ -3535,8 +3578,7 @@
__ Ret();
} else {
WriteInt32ToHeapNumberStub stub(value, r0, r3);
- MaybeObject* stub_code = masm()->TryTailCallStub(&stub);
- if (stub_code->IsFailure()) return stub_code;
+ __ TailCallStub(&stub);
}
} else if (array_type == kExternalUnsignedIntArray) {
// The test is different for unsigned int values. Since we need
@@ -3581,12 +3623,12 @@
__ bind(&box_int_0);
// Integer does not have leading zeros.
- GenerateUInt2Double(masm(), hiword, loword, r4, 0);
+ GenerateUInt2Double(masm, hiword, loword, r4, 0);
__ b(&done);
__ bind(&box_int_1);
// Integer has one leading zero.
- GenerateUInt2Double(masm(), hiword, loword, r4, 1);
+ GenerateUInt2Double(masm, hiword, loword, r4, 1);
__ bind(&done);
@@ -3708,7 +3750,7 @@
// Slow case, key and receiver still in r0 and r1.
__ bind(&slow);
__ IncrementCounter(
- masm()->isolate()->counters()->keyed_load_external_array_slow(),
+ masm->isolate()->counters()->keyed_load_external_array_slow(),
1, r2, r3);
// ---------- S t a t e --------------
@@ -3721,21 +3763,23 @@
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
- return GetCode(flags);
+ __ bind(&miss_force_generic);
+ Code* stub = masm->isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_MissForceGeneric);
+ __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
}
-MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- JSObject* receiver_object,
- ExternalArrayType array_type,
- Code::Flags flags) {
+void KeyedStoreStubCompiler::GenerateStoreExternalArray(
+ MacroAssembler* masm,
+ ExternalArrayType array_type) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
- Label slow, check_heap_number;
+ Label slow, check_heap_number, miss_force_generic;
// Register usage.
Register value = r0;
@@ -3743,25 +3787,20 @@
Register receiver = r2;
// r3 mostly holds the elements array or the destination external array.
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
-
- // Make sure that we've got the right map.
- __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ cmp(r3, Operand(Handle<Map>(receiver_object->map())));
- __ b(ne, &slow);
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the key is a smi.
- __ JumpIfNotSmi(key, &slow);
+ __ JumpIfNotSmi(key, &miss_force_generic);
// Check that the index is in range
__ SmiUntag(r4, key);
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(r4, ip);
// Unsigned comparison catches both negative and too-large values.
- __ b(hs, &slow);
+ __ b(hs, &miss_force_generic);
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
@@ -3799,7 +3838,7 @@
break;
case kExternalFloatArray:
// Perform int-to-float conversion and store to memory.
- StoreIntAsFloat(masm(), r3, r4, r5, r6, r7, r9);
+ StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break;
case kExternalDoubleArray:
__ add(r3, r3, Operand(r4, LSL, 3));
@@ -3811,7 +3850,7 @@
destination = FloatingPointHelper::kCoreRegisters;
}
FloatingPointHelper::ConvertIntToDouble(
- masm(), r5, destination,
+ masm, r5, destination,
d0, r6, r7, // These are: double_dst, dst1, dst2.
r4, s2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kVFPRegisters) {
@@ -4038,28 +4077,137 @@
}
}
- // Slow case: call runtime.
+ // Slow case, key and receiver still in r0 and r1.
__ bind(&slow);
+ __ IncrementCounter(
+ masm->isolate()->counters()->keyed_load_external_array_slow(),
+ 1, r2, r3);
- // Entry registers are intact.
// ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
// -- lr : return address
+ // -- r0 : key
+ // -- r1 : receiver
+ // -----------------------------------
+ Handle<Code> slow_ic =
+ masm->isolate()->builtins()->KeyedStoreIC_Slow();
+ __ Jump(slow_ic, RelocInfo::CODE_TARGET);
+
+ // Miss case, call the runtime.
+ __ bind(&miss_force_generic);
+
+ // ---------- S t a t e --------------
+ // -- lr : return address
+ // -- r0 : key
+ // -- r1 : receiver
// -----------------------------------
- // Push receiver, key and value for runtime call.
- __ Push(r2, r1, r0);
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ Jump(miss_ic, RelocInfo::CODE_TARGET);
+}
- __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
- __ mov(r0, Operand(Smi::FromInt(
- Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)));
- __ Push(r1, r0);
- __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
+void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- r0 : key
+ // -- r1 : receiver
+ // -----------------------------------
+ Label miss_force_generic;
- return GetCode(flags);
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(r0, &miss_force_generic);
+
+ // Get the elements array.
+ __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
+ __ AssertFastElements(r2);
+
+ // Check that the key is within bounds.
+ __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
+ __ cmp(r0, Operand(r3));
+ __ b(hs, &miss_force_generic);
+
+ // Load the result and make sure it's not the hole.
+ __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ __ ldr(r4,
+ MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ cmp(r4, ip);
+ __ b(eq, &miss_force_generic);
+ __ mov(r0, r4);
+ __ Ret();
+
+ __ bind(&miss_force_generic);
+ Code* stub = masm->isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_MissForceGeneric);
+ __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
+}
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
+ bool is_js_array) {
+ // ----------- S t a t e -------------
+ // -- r0 : value
+ // -- r1 : key
+ // -- r2 : receiver
+ // -- lr : return address
+ // -- r3 : scratch
+ // -- r4 : scratch (elements)
+ // -----------------------------------
+ Label miss_force_generic;
+
+ Register value_reg = r0;
+ Register key_reg = r1;
+ Register receiver_reg = r2;
+ Register scratch = r3;
+ Register elements_reg = r4;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(r0, &miss_force_generic);
+
+ // Get the elements array and make sure it is a fast element array, not 'cow'.
+ __ ldr(elements_reg,
+ FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
+ __ CheckMap(elements_reg,
+ scratch,
+ Heap::kFixedArrayMapRootIndex,
+ &miss_force_generic,
+ DONT_DO_SMI_CHECK);
+
+ // Check that the key is within bounds.
+ if (is_js_array) {
+ __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
+ } else {
+ __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
+ }
+ // Compare smis.
+ __ cmp(key_reg, scratch);
+ __ b(hs, &miss_force_generic);
+
+ __ add(scratch,
+ elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ __ str(value_reg,
+ MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
+ __ RecordWrite(scratch,
+ Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize),
+ receiver_reg , elements_reg);
+
+ // value_reg (r0) is preserved.
+ // Done.
+ __ Ret();
+
+ __ bind(&miss_force_generic);
+ Handle<Code> ic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ Jump(ic, RelocInfo::CODE_TARGET);
}
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 69608e9..f0e7bbc 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -199,6 +199,7 @@
// Installs the contents of the native .js files on the global objects.
// Used for creating a context from scratch.
void InstallNativeFunctions();
+ void InstallExperimentalNativeFunctions();
bool InstallNatives();
bool InstallExperimentalNatives();
void InstallBuiltinFunctionIds();
@@ -362,23 +363,24 @@
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
{ // Add length.
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionLength);
- CallbacksDescriptor d(*factory()->length_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionLength);
+ CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes);
descriptors->Set(0, &d);
}
{ // Add name.
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionName);
- CallbacksDescriptor d(*factory()->name_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionName);
+ CallbacksDescriptor d(*factory()->name_symbol(), *foreign, attributes);
descriptors->Set(1, &d);
}
{ // Add arguments.
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionArguments);
- CallbacksDescriptor d(*factory()->arguments_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign =
+ factory()->NewForeign(&Accessors::FunctionArguments);
+ CallbacksDescriptor d(*factory()->arguments_symbol(), *foreign, attributes);
descriptors->Set(2, &d);
}
{ // Add caller.
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionCaller);
- CallbacksDescriptor d(*factory()->caller_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionCaller);
+ CallbacksDescriptor d(*factory()->caller_symbol(), *foreign, attributes);
descriptors->Set(3, &d);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
@@ -386,8 +388,9 @@
if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
}
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionPrototype);
- CallbacksDescriptor d(*factory()->prototype_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign =
+ factory()->NewForeign(&Accessors::FunctionPrototype);
+ CallbacksDescriptor d(*factory()->prototype_symbol(), *foreign, attributes);
descriptors->Set(4, &d);
}
descriptors->Sort();
@@ -509,13 +512,13 @@
DONT_ENUM | DONT_DELETE | READ_ONLY);
{ // length
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionLength);
- CallbacksDescriptor d(*factory()->length_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionLength);
+ CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes);
descriptors->Set(0, &d);
}
{ // name
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionName);
- CallbacksDescriptor d(*factory()->name_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionName);
+ CallbacksDescriptor d(*factory()->name_symbol(), *foreign, attributes);
descriptors->Set(1, &d);
}
{ // arguments
@@ -534,8 +537,9 @@
if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
}
- Handle<Proxy> proxy = factory()->NewProxy(&Accessors::FunctionPrototype);
- CallbacksDescriptor d(*factory()->prototype_symbol(), *proxy, attributes);
+ Handle<Foreign> foreign =
+ factory()->NewForeign(&Accessors::FunctionPrototype);
+ CallbacksDescriptor d(*factory()->prototype_symbol(), *foreign, attributes);
descriptors->Set(4, &d);
}
@@ -846,10 +850,10 @@
// is 1.
array_function->shared()->set_length(1);
Handle<DescriptorArray> array_descriptors =
- factory->CopyAppendProxyDescriptor(
+ factory->CopyAppendForeignDescriptor(
factory->empty_descriptor_array(),
factory->length_symbol(),
- factory->NewProxy(&Accessors::ArrayLength),
+ factory->NewForeign(&Accessors::ArrayLength),
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
// Cache the fast JavaScript array map
@@ -889,10 +893,10 @@
global_context()->set_string_function(*string_fun);
// Add 'length' property to strings.
Handle<DescriptorArray> string_descriptors =
- factory->CopyAppendProxyDescriptor(
+ factory->CopyAppendForeignDescriptor(
factory->empty_descriptor_array(),
factory->length_symbol(),
- factory->NewProxy(&Accessors::StringLength),
+ factory->NewForeign(&Accessors::StringLength),
static_cast<PropertyAttributes>(DONT_ENUM |
DONT_DELETE |
READ_ONLY));
@@ -1285,6 +1289,12 @@
INSTALL_NATIVE(JSObject, "functionCache", function_cache);
}
+void Genesis::InstallExperimentalNativeFunctions() {
+ if (FLAG_harmony_proxies) {
+ INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
+ }
+}
+
#undef INSTALL_NATIVE
@@ -1351,104 +1361,108 @@
// Add 'source' and 'data' property to scripts.
PropertyAttributes common_attributes =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Handle<Proxy> proxy_source = factory()->NewProxy(&Accessors::ScriptSource);
+ Handle<Foreign> foreign_source =
+ factory()->NewForeign(&Accessors::ScriptSource);
Handle<DescriptorArray> script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
factory()->empty_descriptor_array(),
factory()->LookupAsciiSymbol("source"),
- proxy_source,
+ foreign_source,
common_attributes);
- Handle<Proxy> proxy_name = factory()->NewProxy(&Accessors::ScriptName);
+ Handle<Foreign> foreign_name =
+ factory()->NewForeign(&Accessors::ScriptName);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("name"),
- proxy_name,
+ foreign_name,
common_attributes);
- Handle<Proxy> proxy_id = factory()->NewProxy(&Accessors::ScriptId);
+ Handle<Foreign> foreign_id = factory()->NewForeign(&Accessors::ScriptId);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("id"),
- proxy_id,
+ foreign_id,
common_attributes);
- Handle<Proxy> proxy_line_offset =
- factory()->NewProxy(&Accessors::ScriptLineOffset);
+ Handle<Foreign> foreign_line_offset =
+ factory()->NewForeign(&Accessors::ScriptLineOffset);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("line_offset"),
- proxy_line_offset,
+ foreign_line_offset,
common_attributes);
- Handle<Proxy> proxy_column_offset =
- factory()->NewProxy(&Accessors::ScriptColumnOffset);
+ Handle<Foreign> foreign_column_offset =
+ factory()->NewForeign(&Accessors::ScriptColumnOffset);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("column_offset"),
- proxy_column_offset,
+ foreign_column_offset,
common_attributes);
- Handle<Proxy> proxy_data = factory()->NewProxy(&Accessors::ScriptData);
+ Handle<Foreign> foreign_data =
+ factory()->NewForeign(&Accessors::ScriptData);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("data"),
- proxy_data,
+ foreign_data,
common_attributes);
- Handle<Proxy> proxy_type = factory()->NewProxy(&Accessors::ScriptType);
+ Handle<Foreign> foreign_type =
+ factory()->NewForeign(&Accessors::ScriptType);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("type"),
- proxy_type,
+ foreign_type,
common_attributes);
- Handle<Proxy> proxy_compilation_type =
- factory()->NewProxy(&Accessors::ScriptCompilationType);
+ Handle<Foreign> foreign_compilation_type =
+ factory()->NewForeign(&Accessors::ScriptCompilationType);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("compilation_type"),
- proxy_compilation_type,
+ foreign_compilation_type,
common_attributes);
- Handle<Proxy> proxy_line_ends =
- factory()->NewProxy(&Accessors::ScriptLineEnds);
+ Handle<Foreign> foreign_line_ends =
+ factory()->NewForeign(&Accessors::ScriptLineEnds);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("line_ends"),
- proxy_line_ends,
+ foreign_line_ends,
common_attributes);
- Handle<Proxy> proxy_context_data =
- factory()->NewProxy(&Accessors::ScriptContextData);
+ Handle<Foreign> foreign_context_data =
+ factory()->NewForeign(&Accessors::ScriptContextData);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("context_data"),
- proxy_context_data,
+ foreign_context_data,
common_attributes);
- Handle<Proxy> proxy_eval_from_script =
- factory()->NewProxy(&Accessors::ScriptEvalFromScript);
+ Handle<Foreign> foreign_eval_from_script =
+ factory()->NewForeign(&Accessors::ScriptEvalFromScript);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("eval_from_script"),
- proxy_eval_from_script,
+ foreign_eval_from_script,
common_attributes);
- Handle<Proxy> proxy_eval_from_script_position =
- factory()->NewProxy(&Accessors::ScriptEvalFromScriptPosition);
+ Handle<Foreign> foreign_eval_from_script_position =
+ factory()->NewForeign(&Accessors::ScriptEvalFromScriptPosition);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("eval_from_script_position"),
- proxy_eval_from_script_position,
+ foreign_eval_from_script_position,
common_attributes);
- Handle<Proxy> proxy_eval_from_function_name =
- factory()->NewProxy(&Accessors::ScriptEvalFromFunctionName);
+ Handle<Foreign> foreign_eval_from_function_name =
+ factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName);
script_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
script_descriptors,
factory()->LookupAsciiSymbol("eval_from_function_name"),
- proxy_eval_from_function_name,
+ foreign_eval_from_function_name,
common_attributes);
Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
@@ -1501,10 +1515,10 @@
// Make "length" magic on instances.
Handle<DescriptorArray> array_descriptors =
- factory()->CopyAppendProxyDescriptor(
+ factory()->CopyAppendForeignDescriptor(
factory()->empty_descriptor_array(),
factory()->length_symbol(),
- factory()->NewProxy(&Accessors::ArrayLength),
+ factory()->NewForeign(&Accessors::ArrayLength),
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
array_function->initial_map()->set_instance_descriptors(
@@ -1647,6 +1661,9 @@
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
}
+
+ InstallExperimentalNativeFunctions();
+
return true;
}
diff --git a/src/builtins.cc b/src/builtins.cc
index f473559..c398aa3 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 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:
@@ -1341,8 +1341,18 @@
}
+static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
+ KeyedLoadIC::GenerateRuntimeGetProperty(masm);
+}
+
+
static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
- KeyedLoadIC::GenerateMiss(masm);
+ KeyedLoadIC::GenerateMiss(masm, false);
+}
+
+
+static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
+ KeyedLoadIC::GenerateMiss(masm, true);
}
@@ -1431,7 +1441,17 @@
static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
- KeyedStoreIC::GenerateMiss(masm);
+ KeyedStoreIC::GenerateMiss(masm, false);
+}
+
+
+static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
+ KeyedStoreIC::GenerateMiss(masm, true);
+}
+
+
+static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
+ KeyedStoreIC::GenerateSlow(masm);
}
diff --git a/src/builtins.h b/src/builtins.h
index a84eb31..0d733d8 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -1,4 +1,4 @@
-// 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:
@@ -67,115 +67,122 @@
// Define list of builtins implemented in assembly.
-#define BUILTIN_LIST_A(V) \
- V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(JSConstructCall, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(JSConstructStubApi, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(LazyCompile, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(LazyRecompile, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(NotifyOSR, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- \
- V(LoadIC_Miss, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- \
- V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- \
- V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC, \
- Code::kNoExtraICState) \
- V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- \
- V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
- kStrictMode) \
- V(StoreIC_ArrayLength_Strict, STORE_IC, MONOMORPHIC, \
- kStrictMode) \
- V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \
- kStrictMode) \
- V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \
- kStrictMode) \
- V(StoreIC_GlobalProxy_Strict, STORE_IC, MEGAMORPHIC, \
- kStrictMode) \
- \
- V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC, \
- Code::kNoExtraICState) \
- \
- V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED, \
- kStrictMode) \
- V(KeyedStoreIC_Generic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \
- kStrictMode) \
- \
- /* Uses KeyedLoadIC_Initialize; must be after in list. */ \
- V(FunctionCall, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(FunctionApply, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- \
- V(ArrayCode, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(ArrayConstructCode, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- \
- V(StringConstructCode, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- \
- V(OnStackReplacement, BUILTIN, UNINITIALIZED, \
+#define BUILTIN_LIST_A(V) \
+ V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(JSConstructCall, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(JSConstructStubApi, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(LazyCompile, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(LazyRecompile, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(NotifyOSR, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ \
+ V(LoadIC_Miss, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_MissForceGeneric, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_Slow, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedStoreIC_MissForceGeneric, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedStoreIC_Slow, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ \
+ V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ \
+ V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \
+ Code::kNoExtraICState) \
+ V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
+ kStrictMode) \
+ V(StoreIC_ArrayLength_Strict, STORE_IC, MONOMORPHIC, \
+ kStrictMode) \
+ V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \
+ kStrictMode) \
+ V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \
+ kStrictMode) \
+ V(StoreIC_GlobalProxy_Strict, STORE_IC, MEGAMORPHIC, \
+ kStrictMode) \
+ \
+ V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC, \
+ Code::kNoExtraICState) \
+ \
+ V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED, \
+ kStrictMode) \
+ V(KeyedStoreIC_Generic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \
+ kStrictMode) \
+ \
+ /* Uses KeyedLoadIC_Initialize; must be after in list. */ \
+ V(FunctionCall, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(FunctionApply, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ \
+ V(ArrayCode, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(ArrayConstructCode, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ \
+ V(StringConstructCode, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ \
+ V(OnStackReplacement, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState)
@@ -237,8 +244,7 @@
V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \
- V(APPLY_OVERFLOW, 1) \
- V(DERIVED_GET_TRAP, 2)
+ V(APPLY_OVERFLOW, 1)
class BuiltinFunctionTable;
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 7f08d22..d12def8 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 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:
@@ -29,6 +29,7 @@
#include "bootstrapper.h"
#include "code-stubs.h"
+#include "stub-cache.h"
#include "factory.h"
#include "gdb-jit.h"
#include "macro-assembler.h"
@@ -243,4 +244,24 @@
}
+void KeyedLoadFastElementStub::Generate(MacroAssembler* masm) {
+ KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
+}
+
+
+void KeyedStoreFastElementStub::Generate(MacroAssembler* masm) {
+ KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
+}
+
+
+void KeyedLoadExternalArrayStub::Generate(MacroAssembler* masm) {
+ KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, array_type_);
+}
+
+
+void KeyedStoreExternalArrayStub::Generate(MacroAssembler* masm) {
+ KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, array_type_);
+}
+
+
} } // namespace v8::internal
diff --git a/src/code-stubs.h b/src/code-stubs.h
index f16a8db..9074793 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -66,6 +66,10 @@
V(NumberToString) \
V(CEntry) \
V(JSEntry) \
+ V(KeyedLoadFastElement) \
+ V(KeyedStoreFastElement) \
+ V(KeyedLoadExternalArray) \
+ V(KeyedStoreExternalArray) \
V(DebuggerStatement) \
V(StringDictionaryNegativeLookup)
@@ -922,6 +926,86 @@
DISALLOW_COPY_AND_ASSIGN(AllowStubCallsScope);
};
+#ifdef DEBUG
+#define DECLARE_ARRAY_STUB_PRINT(name) void Print() { PrintF(#name); }
+#else
+#define DECLARE_ARRAY_STUB_PRINT(name)
+#endif
+
+
+class KeyedLoadFastElementStub : public CodeStub {
+ public:
+ explicit KeyedLoadFastElementStub() {
+ }
+
+ Major MajorKey() { return KeyedLoadFastElement; }
+ int MinorKey() { return 0; }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "KeyedLoadFastElementStub"; }
+
+ DECLARE_ARRAY_STUB_PRINT(KeyedLoadFastElementStub)
+};
+
+
+class KeyedStoreFastElementStub : public CodeStub {
+ public:
+ explicit KeyedStoreFastElementStub(bool is_js_array)
+ : is_js_array_(is_js_array) { }
+
+ Major MajorKey() { return KeyedStoreFastElement; }
+ int MinorKey() { return is_js_array_ ? 1 : 0; }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "KeyedStoreFastElementStub"; }
+
+ DECLARE_ARRAY_STUB_PRINT(KeyedStoreFastElementStub)
+
+ private:
+ bool is_js_array_;
+};
+
+
+class KeyedLoadExternalArrayStub : public CodeStub {
+ public:
+ explicit KeyedLoadExternalArrayStub(ExternalArrayType array_type)
+ : array_type_(array_type) { }
+
+ Major MajorKey() { return KeyedLoadExternalArray; }
+ int MinorKey() { return array_type_; }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "KeyedLoadExternalArrayStub"; }
+
+ DECLARE_ARRAY_STUB_PRINT(KeyedLoadExternalArrayStub)
+
+ protected:
+ ExternalArrayType array_type_;
+};
+
+
+class KeyedStoreExternalArrayStub : public CodeStub {
+ public:
+ explicit KeyedStoreExternalArrayStub(ExternalArrayType array_type)
+ : array_type_(array_type) { }
+
+ Major MajorKey() { return KeyedStoreExternalArray; }
+ int MinorKey() { return array_type_; }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "KeyedStoreExternalArrayStub"; }
+
+ DECLARE_ARRAY_STUB_PRINT(KeyedStoreExternalArrayStub)
+
+ protected:
+ ExternalArrayType array_type_;
+};
+
+
} } // namespace v8::internal
#endif // V8_CODE_STUBS_H_
diff --git a/src/compiler.cc b/src/compiler.cc
index c57510d..51c2149 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -94,6 +94,7 @@
}
+// Disable optimization for the rest of the compilation pipeline.
void CompilationInfo::DisableOptimization() {
bool is_optimizable_closure =
FLAG_optimize_closures &&
@@ -105,6 +106,14 @@
}
+void CompilationInfo::AbortOptimization() {
+ Handle<Code> code(shared_info()->code());
+ SetCode(code);
+ Isolate* isolate = code->GetIsolate();
+ isolate->compilation_cache()->MarkForLazyOptimizing(closure());
+}
+
+
// Determine whether to use the full compiler for all code. If the flag
// --always-full-compiler is specified this is the case. For the virtual frame
// based compiler the full compiler is also used if a debugger is connected, as
@@ -156,31 +165,6 @@
}
-static void AbortAndDisable(CompilationInfo* info) {
- // Disable optimization for the shared function info and mark the
- // code as non-optimizable. The marker on the shared function info
- // is there because we flush non-optimized code thereby loosing the
- // non-optimizable information for the code. When the code is
- // regenerated and set on the shared function info it is marked as
- // non-optimizable if optimization is disabled for the shared
- // function info.
- Handle<SharedFunctionInfo> shared = info->shared_info();
- shared->set_optimization_disabled(true);
- Handle<Code> code = Handle<Code>(shared->code());
- ASSERT(code->kind() == Code::FUNCTION);
- code->set_optimizable(false);
- info->SetCode(code);
- Isolate* isolate = code->GetIsolate();
- isolate->compilation_cache()->MarkForLazyOptimizing(info->closure());
- if (FLAG_trace_opt) {
- PrintF("[disabled optimization for: ");
- info->closure()->PrintName();
- PrintF(" / %" V8PRIxPTR "]\n",
- reinterpret_cast<intptr_t>(*info->closure()));
- }
-}
-
-
static bool MakeCrankshaftCode(CompilationInfo* info) {
// Test if we can optimize this function when asked to. We can only
// do this after the scopes are computed.
@@ -214,7 +198,9 @@
const int kMaxOptCount =
FLAG_deopt_every_n_times == 0 ? Compiler::kDefaultMaxOptCount : 1000;
if (info->shared_info()->opt_count() > kMaxOptCount) {
- AbortAndDisable(info);
+ info->AbortOptimization();
+ Handle<JSFunction> closure = info->closure();
+ info->shared_info()->DisableOptimization(*closure);
// True indicates the compilation pipeline is still going, not
// necessarily that we optimized the code.
return true;
@@ -231,7 +217,9 @@
Scope* scope = info->scope();
if ((scope->num_parameters() + 1) > limit ||
scope->num_stack_slots() > limit) {
- AbortAndDisable(info);
+ info->AbortOptimization();
+ Handle<JSFunction> closure = info->closure();
+ info->shared_info()->DisableOptimization(*closure);
// True indicates the compilation pipeline is still going, not
// necessarily that we optimized the code.
return true;
@@ -304,9 +292,14 @@
}
}
- // Compilation with the Hydrogen compiler failed. Keep using the
- // shared code but mark it as unoptimizable.
- AbortAndDisable(info);
+ // Keep using the shared code.
+ info->AbortOptimization();
+ if (!builder.inline_bailout()) {
+ // Mark the shared code as unoptimizable unless it was an inlined
+ // function that bailed out.
+ Handle<JSFunction> closure = info->closure();
+ info->shared_info()->DisableOptimization(*closure);
+ }
// True indicates the compilation pipeline is still going, not necessarily
// that we optimized the code.
return true;
diff --git a/src/compiler.h b/src/compiler.h
index 1c02f68..6a2d48f 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -144,6 +144,10 @@
return V8::UseCrankshaft() && !closure_.is_null();
}
+ // Disable all optimization attempts of this info for the rest of the
+ // current compilation pipeline.
+ void AbortOptimization();
+
private:
Isolate* isolate_;
diff --git a/src/contexts.h b/src/contexts.h
index 4b07726..b0d3ae4 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -107,7 +107,8 @@
V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data) \
- V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings)
+ V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
+ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
@@ -238,6 +239,7 @@
MAP_CACHE_INDEX,
CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
+ DERIVED_GET_TRAP_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 8d11e7a..f54e3e8 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -244,7 +244,7 @@
// A paranoid check to make sure that we don't get a memory overrun
// in case of frames_count having a wild value.
if (record.sample.frames_count < 0
- || record.sample.frames_count >= TickSample::kMaxFramesCount)
+ || record.sample.frames_count > TickSample::kMaxFramesCount)
record.sample.frames_count = 0;
generator_->RecordTickSample(record.sample);
ticks_buffer_.FinishDequeue();
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 9481d3b..f9f6167 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -134,8 +134,8 @@
// methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public Thread {
public:
- explicit ProfilerEventsProcessor(Isolate* isolate,
- ProfileGenerator* generator);
+ ProfilerEventsProcessor(Isolate* isolate,
+ ProfileGenerator* generator);
virtual ~ProfilerEventsProcessor() {}
// Thread control.
diff --git a/src/debug.cc b/src/debug.cc
index 6de237d..2ac4bff 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -168,6 +168,7 @@
Code* code = Code::GetCodeFromTargetAddress(target);
if ((code->is_inline_cache_stub() &&
!code->is_type_recording_binary_op_stub() &&
+ !code->is_type_recording_unary_op_stub() &&
!code->is_compare_ic_stub()) ||
RelocInfo::IsConstructCall(rmode())) {
break_point_++;
@@ -2365,7 +2366,7 @@
Handle<Object> exec_state,
Handle<Object> event_data,
v8::Debug::ClientData* client_data) {
- if (event_listener_->IsProxy()) {
+ if (event_listener_->IsForeign()) {
CallCEventCallback(event, exec_state, event_data, client_data);
} else {
CallJSEventCallback(event, exec_state, event_data);
@@ -2377,9 +2378,9 @@
Handle<Object> exec_state,
Handle<Object> event_data,
v8::Debug::ClientData* client_data) {
- Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
+ Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
v8::Debug::EventCallback2 callback =
- FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->proxy());
+ FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->address());
EventDetailsImpl event_details(
event,
Handle<JSObject>::cast(exec_state),
diff --git a/src/extensions/experimental/datetime-format.cc b/src/extensions/experimental/datetime-format.cc
new file mode 100644
index 0000000..ad8986a
--- /dev/null
+++ b/src/extensions/experimental/datetime-format.cc
@@ -0,0 +1,381 @@
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "datetime-format.h"
+
+#include "i18n-utils.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/dtptngen.h"
+#include "unicode/locid.h"
+#include "unicode/smpdtfmt.h"
+
+namespace v8 {
+namespace internal {
+
+v8::Persistent<v8::FunctionTemplate> DateTimeFormat::datetime_format_template_;
+
+static icu::DateFormat* CreateDateTimeFormat(v8::Handle<v8::String>,
+ v8::Handle<v8::Object>);
+static v8::Handle<v8::Value> GetSymbols(
+ const v8::Arguments&,
+ const icu::UnicodeString*, int32_t,
+ const icu::UnicodeString*, int32_t,
+ const icu::UnicodeString*, int32_t);
+static v8::Handle<v8::Value> ThrowUnexpectedObjectError();
+static icu::DateFormat::EStyle GetDateTimeStyle(const icu::UnicodeString&);
+
+icu::SimpleDateFormat* DateTimeFormat::UnpackDateTimeFormat(
+ v8::Handle<v8::Object> obj) {
+ if (datetime_format_template_->HasInstance(obj)) {
+ return static_cast<icu::SimpleDateFormat*>(
+ obj->GetPointerFromInternalField(0));
+ }
+
+ return NULL;
+}
+
+void DateTimeFormat::DeleteDateTimeFormat(v8::Persistent<v8::Value> object,
+ void* param) {
+ v8::Persistent<v8::Object> persistent_object =
+ v8::Persistent<v8::Object>::Cast(object);
+
+ // First delete the hidden C++ object.
+ // Unpacking should never return NULL here. That would only happen if
+ // this method is used as the weak callback for persistent handles not
+ // pointing to a date time formatter.
+ delete UnpackDateTimeFormat(persistent_object);
+
+ // Then dispose of the persistent handle to JS object.
+ persistent_object.Dispose();
+}
+
+v8::Handle<v8::Value> DateTimeFormat::Format(const v8::Arguments& args) {
+ v8::HandleScope handle_scope;
+
+ double millis = 0.0;
+ if (args.Length() != 1 || !args[0]->IsDate()) {
+ // Create a new date.
+ v8::TryCatch try_catch;
+ v8::Local<v8::Script> date_script =
+ v8::Script::Compile(v8::String::New("eval('new Date()')"));
+ millis = date_script->Run()->NumberValue();
+ if (try_catch.HasCaught()) {
+ return try_catch.ReThrow();
+ }
+ } else {
+ millis = v8::Date::Cast(*args[0])->NumberValue();
+ }
+
+ icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
+ if (!date_format) {
+ return ThrowUnexpectedObjectError();
+ }
+
+ icu::UnicodeString result;
+ date_format->format(millis, result);
+
+ return v8::String::New(
+ reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length());
+}
+
+v8::Handle<v8::Value> DateTimeFormat::GetMonths(const v8::Arguments& args) {
+ icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
+ if (!date_format) {
+ return ThrowUnexpectedObjectError();
+ }
+
+ const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
+
+ int32_t narrow_count;
+ const icu::UnicodeString* narrow = symbols->getMonths(
+ narrow_count,
+ icu::DateFormatSymbols::STANDALONE,
+ icu::DateFormatSymbols::NARROW);
+ int32_t abbrev_count;
+ const icu::UnicodeString* abbrev = symbols->getMonths(
+ abbrev_count,
+ icu::DateFormatSymbols::STANDALONE,
+ icu::DateFormatSymbols::ABBREVIATED);
+ int32_t wide_count;
+ const icu::UnicodeString* wide = symbols->getMonths(
+ wide_count,
+ icu::DateFormatSymbols::STANDALONE,
+ icu::DateFormatSymbols::WIDE);
+
+ return GetSymbols(
+ args, narrow, narrow_count, abbrev, abbrev_count, wide, wide_count);
+}
+
+v8::Handle<v8::Value> DateTimeFormat::GetWeekdays(const v8::Arguments& args) {
+ icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
+ if (!date_format) {
+ ThrowUnexpectedObjectError();
+ }
+
+ const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
+
+ int32_t narrow_count;
+ const icu::UnicodeString* narrow = symbols->getWeekdays(
+ narrow_count,
+ icu::DateFormatSymbols::STANDALONE,
+ icu::DateFormatSymbols::NARROW);
+ int32_t abbrev_count;
+ const icu::UnicodeString* abbrev = symbols->getWeekdays(
+ abbrev_count,
+ icu::DateFormatSymbols::STANDALONE,
+ icu::DateFormatSymbols::ABBREVIATED);
+ int32_t wide_count;
+ const icu::UnicodeString* wide = symbols->getWeekdays(
+ wide_count,
+ icu::DateFormatSymbols::STANDALONE,
+ icu::DateFormatSymbols::WIDE);
+
+ // getXXXWeekdays always returns 8 elements.
+ ASSERT_EQ(8, narrow_count);
+ ASSERT_EQ(8, abbrev_count);
+ ASSERT_EQ(8, wide_count);
+
+ // ICU documentation says we should ignore element 0 of the returned array.
+ return GetSymbols(args, narrow + 1, narrow_count - 1, abbrev + 1,
+ abbrev_count -1 , wide + 1, wide_count - 1);
+}
+
+v8::Handle<v8::Value> DateTimeFormat::GetEras(const v8::Arguments& args) {
+ icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
+ if (!date_format) {
+ return ThrowUnexpectedObjectError();
+ }
+
+ const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
+
+ int32_t narrow_count;
+ const icu::UnicodeString* narrow = symbols->getNarrowEras(narrow_count);
+ int32_t abbrev_count;
+ const icu::UnicodeString* abbrev = symbols->getEras(abbrev_count);
+ int32_t wide_count;
+ const icu::UnicodeString* wide = symbols->getEraNames(wide_count);
+
+ return GetSymbols(
+ args, narrow, narrow_count, abbrev, abbrev_count, wide, wide_count);
+}
+
+v8::Handle<v8::Value> DateTimeFormat::GetAmPm(const v8::Arguments& args) {
+ icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
+ if (!date_format) {
+ return ThrowUnexpectedObjectError();
+ }
+
+ const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
+
+ // In this case narrow == abbreviated == wide
+ int32_t count;
+ const icu::UnicodeString* wide = symbols->getAmPmStrings(count);
+
+ return GetSymbols(args, wide, count, wide, count, wide, count);
+}
+
+v8::Handle<v8::Value> DateTimeFormat::JSDateTimeFormat(
+ const v8::Arguments& args) {
+ v8::HandleScope handle_scope;
+
+ ASSERT_EQ(2, args.Length());
+ // LanguageID string.
+ ASSERT(args[0]->IsString());
+ // Settings object.
+ ASSERT(args[1]->IsObject());
+
+ icu::SimpleDateFormat* date_format = static_cast<icu::SimpleDateFormat*>(
+ CreateDateTimeFormat(args[0]->ToString(), args[1]->ToObject()));
+
+ if (datetime_format_template_.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> raw_template(v8::FunctionTemplate::New());
+
+ raw_template->SetClassName(v8::String::New("v8Locale.DateTimeFormat"));
+
+ // Define internal field count on instance template.
+ v8::Local<v8::ObjectTemplate> object_template =
+ raw_template->InstanceTemplate();
+
+ // Set aside internal field for icu date time formatter.
+ object_template->SetInternalFieldCount(1);
+
+ // Define all of the prototype methods on prototype template.
+ v8::Local<v8::ObjectTemplate> proto = raw_template->PrototypeTemplate();
+ proto->Set(v8::String::New("format"),
+ v8::FunctionTemplate::New(Format));
+ proto->Set(v8::String::New("getMonths"),
+ v8::FunctionTemplate::New(GetMonths));
+ proto->Set(v8::String::New("getWeekdays"),
+ v8::FunctionTemplate::New(GetWeekdays));
+ proto->Set(v8::String::New("getEras"),
+ v8::FunctionTemplate::New(GetEras));
+ proto->Set(v8::String::New("getAmPm"),
+ v8::FunctionTemplate::New(GetAmPm));
+
+ datetime_format_template_ =
+ v8::Persistent<v8::FunctionTemplate>::New(raw_template);
+ }
+
+ // Create an empty object wrapper.
+ v8::Local<v8::Object> local_object =
+ datetime_format_template_->GetFunction()->NewInstance();
+ v8::Persistent<v8::Object> wrapper =
+ v8::Persistent<v8::Object>::New(local_object);
+
+ // Set date time formatter as internal field of the resulting JS object.
+ wrapper->SetPointerInInternalField(0, date_format);
+
+ // Set resolved pattern in options.pattern.
+ icu::UnicodeString pattern;
+ date_format->toPattern(pattern);
+ v8::Local<v8::Object> options = v8::Object::New();
+ options->Set(v8::String::New("pattern"),
+ v8::String::New(reinterpret_cast<const uint16_t*>(
+ pattern.getBuffer()), pattern.length()));
+ wrapper->Set(v8::String::New("options"), options);
+
+ // Make object handle weak so we can delete iterator once GC kicks in.
+ wrapper.MakeWeak(NULL, DeleteDateTimeFormat);
+
+ return wrapper;
+}
+
+// Returns SimpleDateFormat.
+static icu::DateFormat* CreateDateTimeFormat(
+ v8::Handle<v8::String> locale, v8::Handle<v8::Object> settings) {
+ v8::HandleScope handle_scope;
+
+ v8::String::AsciiValue ascii_locale(locale);
+ icu::Locale icu_locale(*ascii_locale);
+
+ // Make formatter from skeleton.
+ icu::SimpleDateFormat* date_format = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ icu::UnicodeString skeleton;
+ if (I18NUtils::ExtractStringSetting(settings, "skeleton", &skeleton)) {
+ v8::Local<icu::DateTimePatternGenerator> generator(
+ icu::DateTimePatternGenerator::createInstance(icu_locale, status));
+ icu::UnicodeString pattern =
+ generator->getBestPattern(skeleton, status);
+
+ date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
+ if (U_SUCCESS(status)) {
+ return date_format;
+ } else {
+ delete date_format;
+ }
+ }
+
+ // Extract date type and time type from settings.
+ icu::UnicodeString date_type;
+ icu::DateFormat::EStyle date_style = icu::DateFormat::kNone;
+ if (I18NUtils::ExtractStringSetting(settings, "dateType", &date_type)) {
+ date_style = GetDateTimeStyle(date_type);
+ }
+
+ icu::UnicodeString time_type;
+ icu::DateFormat::EStyle time_style = icu::DateFormat::kNone;
+ if (I18NUtils::ExtractStringSetting(settings, "timeType", &time_type)) {
+ time_style = GetDateTimeStyle(time_type);
+ }
+
+ // Try all combinations of date/time types.
+ if (date_style == icu::DateFormat::kNone &&
+ time_style == icu::DateFormat::kNone) {
+ // Return default short date, short
+ return icu::DateFormat::createDateTimeInstance(
+ icu::DateFormat::kShort, icu::DateFormat::kShort, icu_locale);
+ } else if (date_style != icu::DateFormat::kNone &&
+ time_style != icu::DateFormat::kNone) {
+ return icu::DateFormat::createDateTimeInstance(
+ date_style, time_style, icu_locale);
+ } else if (date_style != icu::DateFormat::kNone) {
+ return icu::DateFormat::createDateInstance(date_style, icu_locale);
+ } else {
+ // time_style != icu::DateFormat::kNone
+ return icu::DateFormat::createTimeInstance(time_style, icu_locale);
+ }
+}
+
+// Creates a v8::Array of narrow, abbrev or wide symbols.
+static v8::Handle<v8::Value> GetSymbols(const v8::Arguments& args,
+ const icu::UnicodeString* narrow,
+ int32_t narrow_count,
+ const icu::UnicodeString* abbrev,
+ int32_t abbrev_count,
+ const icu::UnicodeString* wide,
+ int32_t wide_count) {
+ v8::HandleScope handle_scope;
+
+ // Make wide width default.
+ const icu::UnicodeString* result = wide;
+ int32_t count = wide_count;
+
+ if (args.Length() == 1 && args[0]->IsString()) {
+ v8::String::AsciiValue ascii_value(args[0]);
+ if (strcmp(*ascii_value, "abbreviated") == 0) {
+ result = abbrev;
+ count = abbrev_count;
+ } else if (strcmp(*ascii_value, "narrow") == 0) {
+ result = narrow;
+ count = narrow_count;
+ }
+ }
+
+ v8::Handle<v8::Array> symbols = v8::Array::New();
+ for (int32_t i = 0; i < count; ++i) {
+ symbols->Set(i, v8::String::New(
+ reinterpret_cast<const uint16_t*>(result[i].getBuffer()),
+ result[i].length()));
+ }
+
+ return handle_scope.Close(symbols);
+}
+
+// Throws a JavaScript exception.
+static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
+ // Returns undefined, and schedules an exception to be thrown.
+ return v8::ThrowException(v8::Exception::Error(
+ v8::String::New("DateTimeFormat method called on an object "
+ "that is not a DateTimeFormat.")));
+}
+
+// Returns icu date/time style.
+static icu::DateFormat::EStyle GetDateTimeStyle(
+ const icu::UnicodeString& type) {
+ if (type == UNICODE_STRING_SIMPLE("medium")) {
+ return icu::DateFormat::kMedium;
+ } else if (type == UNICODE_STRING_SIMPLE("long")) {
+ return icu::DateFormat::kLong;
+ } else if (type == UNICODE_STRING_SIMPLE("full")) {
+ return icu::DateFormat::kFull;
+ }
+
+ return icu::DateFormat::kShort;
+}
+
+} } // namespace v8::internal
diff --git a/src/extensions/experimental/datetime-format.h b/src/extensions/experimental/datetime-format.h
new file mode 100644
index 0000000..5b5abf4
--- /dev/null
+++ b/src/extensions/experimental/datetime-format.h
@@ -0,0 +1,83 @@
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_EXTENSIONS_EXPERIMENTAL_DATETIME_FORMAT_H_
+#define V8_EXTENSIONS_EXPERIMENTAL_DATETIME_FORMAT_H_
+
+#include <v8.h>
+
+#include "unicode/uversion.h"
+
+namespace U_ICU_NAMESPACE {
+class SimpleDateFormat;
+}
+
+namespace v8 {
+namespace internal {
+
+class DateTimeFormat {
+ public:
+ static v8::Handle<v8::Value> JSDateTimeFormat(const v8::Arguments& args);
+
+ // Helper methods for various bindings.
+
+ // Unpacks date format object from corresponding JavaScript object.
+ static icu::SimpleDateFormat* UnpackDateTimeFormat(
+ v8::Handle<v8::Object> obj);
+
+ // Release memory we allocated for the DateFormat once the JS object that
+ // holds the pointer gets garbage collected.
+ static void DeleteDateTimeFormat(v8::Persistent<v8::Value> object,
+ void* param);
+
+ // Formats date and returns corresponding string.
+ static v8::Handle<v8::Value> Format(const v8::Arguments& args);
+
+ // All date time symbol methods below return stand-alone names in
+ // either narrow, abbreviated or wide width.
+
+ // Get list of months.
+ static v8::Handle<v8::Value> GetMonths(const v8::Arguments& args);
+
+ // Get list of weekdays.
+ static v8::Handle<v8::Value> GetWeekdays(const v8::Arguments& args);
+
+ // Get list of eras.
+ static v8::Handle<v8::Value> GetEras(const v8::Arguments& args);
+
+ // Get list of day periods.
+ static v8::Handle<v8::Value> GetAmPm(const v8::Arguments& args);
+
+ private:
+ DateTimeFormat();
+
+ static v8::Persistent<v8::FunctionTemplate> datetime_format_template_;
+};
+
+} } // namespace v8::internal
+
+#endif // V8_EXTENSIONS_EXPERIMENTAL_DATETIME_FORMAT_H_
diff --git a/src/extensions/experimental/experimental.gyp b/src/extensions/experimental/experimental.gyp
index 2a7775e..79d55ba 100644
--- a/src/extensions/experimental/experimental.gyp
+++ b/src/extensions/experimental/experimental.gyp
@@ -41,6 +41,8 @@
'break-iterator.h',
'collator.cc',
'collator.h',
+ 'datetime-format.cc',
+ 'datetime-format.h',
'i18n-extension.cc',
'i18n-extension.h',
'i18n-locale.cc',
diff --git a/src/extensions/experimental/i18n-extension.cc b/src/extensions/experimental/i18n-extension.cc
index 88c609e..79affaf 100644
--- a/src/extensions/experimental/i18n-extension.cc
+++ b/src/extensions/experimental/i18n-extension.cc
@@ -29,6 +29,7 @@
#include "break-iterator.h"
#include "collator.h"
+#include "datetime-format.h"
#include "i18n-locale.h"
#include "natives.h"
@@ -59,6 +60,8 @@
return v8::FunctionTemplate::New(BreakIterator::JSBreakIterator);
} else if (name->Equals(v8::String::New("NativeJSCollator"))) {
return v8::FunctionTemplate::New(Collator::JSCollator);
+ } else if (name->Equals(v8::String::New("NativeJSDateTimeFormat"))) {
+ return v8::FunctionTemplate::New(DateTimeFormat::JSDateTimeFormat);
}
return v8::Handle<v8::FunctionTemplate>();
diff --git a/src/extensions/experimental/i18n-utils.cc b/src/extensions/experimental/i18n-utils.cc
index a82c8eb..f00e363 100644
--- a/src/extensions/experimental/i18n-utils.cc
+++ b/src/extensions/experimental/i18n-utils.cc
@@ -29,6 +29,8 @@
#include <string.h>
+#include "unicode/unistr.h"
+
namespace v8 {
namespace internal {
@@ -40,4 +42,27 @@
dest[length - 1] = '\0';
}
+// static
+bool I18NUtils::ExtractStringSetting(const v8::Handle<v8::Object>& settings,
+ const char* setting,
+ icu::UnicodeString* result) {
+ if (!setting || !result) return false;
+
+ v8::HandleScope handle_scope;
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Value> value = settings->Get(v8::String::New(setting));
+ if (try_catch.HasCaught()) {
+ return false;
+ }
+ // No need to check if |value| is empty because it's taken care of
+ // by TryCatch above.
+ if (!value->IsUndefined() && !value->IsNull() && value->IsString()) {
+ v8::String::Utf8Value utf8_value(value);
+ if (*utf8_value == NULL) return false;
+ result->setTo(icu::UnicodeString::fromUTF8(*utf8_value));
+ return true;
+ }
+ return false;
+}
+
} } // namespace v8::internal
diff --git a/src/extensions/experimental/i18n-utils.h b/src/extensions/experimental/i18n-utils.h
index 7702708..b5e215e 100644
--- a/src/extensions/experimental/i18n-utils.h
+++ b/src/extensions/experimental/i18n-utils.h
@@ -28,6 +28,14 @@
#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_
#define V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_
+#include <v8.h>
+
+#include "unicode/uversion.h"
+
+namespace U_ICU_NAMESPACE {
+class UnicodeString;
+}
+
namespace v8 {
namespace internal {
@@ -40,6 +48,12 @@
// TODO(cira): Find a way to use OS::SNPrintF instead.
static void StrNCopy(char* dest, int length, const char* src);
+ // Extract a string setting named in |settings| and set it to |result|.
+ // Return true if it's specified. Otherwise, return false.
+ static bool ExtractStringSetting(const v8::Handle<v8::Object>& settings,
+ const char* setting,
+ icu::UnicodeString* result);
+
private:
I18NUtils() {}
};
diff --git a/src/extensions/experimental/i18n.js b/src/extensions/experimental/i18n.js
index 0fa7ae7..022e763 100644
--- a/src/extensions/experimental/i18n.js
+++ b/src/extensions/experimental/i18n.js
@@ -45,11 +45,11 @@
}
var properties = NativeJSLocale(
- v8Locale.createSettingsOrDefault_(settings, {'localeID': 'root'}));
+ v8Locale.__createSettingsOrDefault(settings, {'localeID': 'root'}));
// Keep the resolved ICU locale ID around to avoid resolving localeID to
// ICU locale ID every time BreakIterator, Collator and so forth are called.
- this.__icuLocaleID__ = properties.icuLocaleID;
+ this.__icuLocaleID = properties.icuLocaleID;
this.options = {'localeID': properties.localeID,
'regionID': properties.regionID};
};
@@ -61,7 +61,7 @@
*/
v8Locale.prototype.derive = function(settings) {
return new v8Locale(
- v8Locale.createSettingsOrDefault_(settings, this.options));
+ v8Locale.__createSettingsOrDefault(settings, this.options));
};
/**
@@ -79,9 +79,9 @@
v8Locale.v8BreakIterator = function(locale, type) {
native function NativeJSBreakIterator();
- locale = v8Locale.createLocaleOrDefault_(locale);
+ locale = v8Locale.__createLocaleOrDefault(locale);
// BCP47 ID would work in this case, but we use ICU locale for consistency.
- var iterator = NativeJSBreakIterator(locale.__icuLocaleID__, type);
+ var iterator = NativeJSBreakIterator(locale.__icuLocaleID, type);
iterator.type = type;
return iterator;
};
@@ -122,22 +122,103 @@
v8Locale.Collator = function(locale, settings) {
native function NativeJSCollator();
- locale = v8Locale.createLocaleOrDefault_(locale);
+ locale = v8Locale.__createLocaleOrDefault(locale);
var collator = NativeJSCollator(
- locale.__icuLocaleID__, v8Locale.createSettingsOrDefault_(settings, {}));
+ locale.__icuLocaleID, v8Locale.__createSettingsOrDefault(settings, {}));
return collator;
};
/**
* Creates new Collator based on current locale.
* @param {Object} - collation flags. See constructor.
- * @returns {Object} - new v8BreakIterator object.
+ * @returns {Object} - new Collator object.
*/
v8Locale.prototype.createCollator = function(settings) {
return new v8Locale.Collator(this, settings);
};
/**
+ * DateTimeFormat class implements locale-aware date and time formatting.
+ * Constructor is not part of public API.
+ * @param {Object} locale - locale object to pass to formatter.
+ * @param {Object} settings - formatting flags:
+ * - skeleton
+ * - dateType
+ * - timeType
+ * - calendar
+ * @constructor
+ */
+v8Locale.__DateTimeFormat = function(locale, settings) {
+ native function NativeJSDateTimeFormat();
+
+ settings = v8Locale.__createSettingsOrDefault(settings, {});
+
+ var cleanSettings = {};
+ if (settings.hasOwnProperty('skeleton')) {
+ cleanSettings['skeleton'] = settings['skeleton'];
+ } else {
+ cleanSettings = {};
+ if (settings.hasOwnProperty('dateType')) {
+ var dt = settings['dateType'];
+ if (!/^short|medium|long|full$/.test(dt)) dt = 'short';
+ cleanSettings['dateType'] = dt;
+ }
+
+ if (settings.hasOwnProperty('timeType')) {
+ var tt = settings['timeType'];
+ if (!/^short|medium|long|full$/.test(tt)) tt = 'short';
+ cleanSettings['timeType'] = tt;
+ }
+ }
+
+ // Default is to show short date and time.
+ if (!cleanSettings.hasOwnProperty('skeleton') &&
+ !cleanSettings.hasOwnProperty('dateType') &&
+ !cleanSettings.hasOwnProperty('timeType')) {
+ cleanSettings = {'dateType': 'short',
+ 'timeType': 'short'};
+ }
+
+ locale = v8Locale.__createLocaleOrDefault(locale);
+ var formatter = NativeJSDateTimeFormat(locale.__icuLocaleID, cleanSettings);
+
+ // NativeJSDateTimeFormat creates formatter.options for us, we just need
+ // to append actual settings to it.
+ for (key in cleanSettings) {
+ formatter.options[key] = cleanSettings[key];
+ }
+
+ /**
+ * Clones existing date time format with possible overrides for some
+ * of the options.
+ * @param {!Object} overrideSettings - overrides for current format settings.
+ * @returns {Object} - new DateTimeFormat object.
+ */
+ formatter.derive = function(overrideSettings) {
+ // To remove a setting user can specify undefined as its value. We'll remove
+ // it from the map in that case.
+ for (var prop in overrideSettings) {
+ if (settings.hasOwnProperty(prop) && !overrideSettings[prop]) {
+ delete settings[prop];
+ }
+ }
+ return new v8Locale.__DateTimeFormat(
+ locale, v8Locale.__createSettingsOrDefault(overrideSettings, settings));
+ };
+
+ return formatter;
+};
+
+/**
+ * Creates new DateTimeFormat based on current locale.
+ * @param {Object} - formatting flags. See constructor.
+ * @returns {Object} - new DateTimeFormat object.
+ */
+v8Locale.prototype.createDateTimeFormat = function(settings) {
+ return new v8Locale.__DateTimeFormat(this, settings);
+};
+
+/**
* Merges user settings and defaults.
* Settings that are not of object type are rejected.
* Actual property values are not validated, but whitespace is trimmed if they
@@ -146,7 +227,7 @@
* @param {!Object} defaults - default values for this type of settings.
* @returns {Object} - valid settings object.
*/
-v8Locale.createSettingsOrDefault_ = function(settings, defaults) {
+v8Locale.__createSettingsOrDefault = function(settings, defaults) {
if (!settings || typeof(settings) !== 'object' ) {
return defaults;
}
@@ -155,11 +236,17 @@
settings[key] = defaults[key];
}
}
- // Clean up values, like trimming whitespace.
+ // Clean up settings.
for (var key in settings) {
+ // Trim whitespace.
if (typeof(settings[key]) === "string") {
settings[key] = settings[key].trim();
}
+ // Remove all properties that are set to undefined/null. This allows
+ // derive method to remove a setting we don't need anymore.
+ if (!settings[key]) {
+ delete settings[key];
+ }
}
return settings;
@@ -171,7 +258,7 @@
* @param {!Object} locale - user provided locale.
* @returns {Object} - v8Locale object.
*/
-v8Locale.createLocaleOrDefault_ = function(locale) {
+v8Locale.__createLocaleOrDefault = function(locale) {
if (!locale || !(locale instanceof v8Locale)) {
return new v8Locale();
} else {
diff --git a/src/factory.cc b/src/factory.cc
index a8634ac..849a2e0 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -266,7 +266,7 @@
heap->SetLastScriptId(Smi::FromInt(id));
// Create and initialize script object.
- Handle<Proxy> wrapper = NewProxy(0, TENURED);
+ Handle<Foreign> wrapper = NewForeign(0, TENURED);
Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
script->set_source(*source);
script->set_name(heap->undefined_value());
@@ -286,15 +286,15 @@
}
-Handle<Proxy> Factory::NewProxy(Address addr, PretenureFlag pretenure) {
+Handle<Foreign> Factory::NewForeign(Address addr, PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->AllocateProxy(addr, pretenure),
- Proxy);
+ isolate()->heap()->AllocateForeign(addr, pretenure),
+ Foreign);
}
-Handle<Proxy> Factory::NewProxy(const AccessorDescriptor* desc) {
- return NewProxy((Address) desc, TENURED);
+Handle<Foreign> Factory::NewForeign(const AccessorDescriptor* desc) {
+ return NewForeign((Address) desc, TENURED);
}
@@ -712,7 +712,7 @@
// Allocate the new array.
-Handle<DescriptorArray> Factory::CopyAppendProxyDescriptor(
+Handle<DescriptorArray> Factory::CopyAppendForeignDescriptor(
Handle<DescriptorArray> array,
Handle<String> key,
Handle<Object> value,
diff --git a/src/factory.h b/src/factory.h
index b1d4682..e2c08ed 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -156,13 +156,13 @@
Handle<Script> NewScript(Handle<String> source);
- // Proxies are pretenured when allocated by the bootstrapper.
- Handle<Proxy> NewProxy(Address addr,
- PretenureFlag pretenure = NOT_TENURED);
+ // Foreign objects are pretenured when allocated by the bootstrapper.
+ Handle<Foreign> NewForeign(Address addr,
+ PretenureFlag pretenure = NOT_TENURED);
- // Allocate a new proxy. The proxy is pretenured (allocated directly in
- // the old generation).
- Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
+ // Allocate a new foreign object. The foreign is pretenured (allocated
+ // directly in the old generation).
+ Handle<Foreign> NewForeign(const AccessorDescriptor* foreign);
Handle<ByteArray> NewByteArray(int length,
PretenureFlag pretenure = NOT_TENURED);
@@ -316,7 +316,7 @@
Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name,
Handle<Code> code);
- Handle<DescriptorArray> CopyAppendProxyDescriptor(
+ Handle<DescriptorArray> CopyAppendForeignDescriptor(
Handle<DescriptorArray> array,
Handle<String> key,
Handle<Object> value,
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index aa1d274..a85f5fe 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -287,10 +287,9 @@
DEFINE_bool(always_compact, false, "Perform compaction on every full GC")
DEFINE_bool(never_compact, false,
"Never perform compaction on full GC - testing only")
-DEFINE_bool(cleanup_ics_at_gc, true,
- "Flush inline caches prior to mark compact collection.")
-DEFINE_bool(cleanup_caches_in_maps_at_gc, true,
- "Flush code caches in maps during mark compact cycle.")
+DEFINE_bool(cleanup_code_caches_at_gc, true,
+ "Flush inline caches prior to mark compact collection and "
+ "flush code caches in maps during mark compact cycle.")
DEFINE_int(random_seed, 0,
"Default seed for initializing random generator "
"(0, the default, means to use system random).")
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 250f127..e4bbc95 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -619,6 +619,11 @@
void GlobalHandles::AddObjectGroup(Object*** handles,
size_t length,
v8::RetainedObjectInfo* info) {
+#ifdef DEBUG
+ for (size_t i = 0; i < length; ++i) {
+ ASSERT(!Node::FromLocation(handles[i])->independent_);
+ }
+#endif
if (length == 0) {
if (info != NULL) info->Dispose();
return;
@@ -630,6 +635,12 @@
void GlobalHandles::AddImplicitReferences(HeapObject** parent,
Object*** children,
size_t length) {
+#ifdef DEBUG
+ ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->independent_);
+ for (size_t i = 0; i < length; ++i) {
+ ASSERT(!Node::FromLocation(children[i])->independent_);
+ }
+#endif
if (length == 0) return;
implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length));
}
diff --git a/src/handles.cc b/src/handles.cc
index 3d5ac20..b03b642 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -544,7 +544,7 @@
// Wrappers for scripts are kept alive and cached in weak global
-// handles referred from proxy objects held by the scripts as long as
+// handles referred from foreign objects held by the scripts as long as
// they are used. When they are not used anymore, the garbage
// collector will call the weak callback on the global handle
// associated with the wrapper and get rid of both the wrapper and the
@@ -557,9 +557,9 @@
#endif
Handle<Object> cache = Utils::OpenHandle(*handle);
JSValue* wrapper = JSValue::cast(*cache);
- Proxy* proxy = Script::cast(wrapper->value())->wrapper();
- ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
- proxy->set_proxy(0);
+ Foreign* foreign = Script::cast(wrapper->value())->wrapper();
+ ASSERT(foreign->address() == reinterpret_cast<Address>(cache.location()));
+ foreign->set_address(0);
Isolate* isolate = Isolate::Current();
isolate->global_handles()->Destroy(cache.location());
isolate->counters()->script_wrappers()->Decrement();
@@ -567,10 +567,10 @@
Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
- if (script->wrapper()->proxy() != NULL) {
+ if (script->wrapper()->address() != NULL) {
// Return the script wrapper directly from the cache.
return Handle<JSValue>(
- reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
+ reinterpret_cast<JSValue**>(script->wrapper()->address()));
}
Isolate* isolate = Isolate::Current();
// Construct a new script wrapper.
@@ -586,7 +586,7 @@
Handle<Object> handle = isolate->global_handles()->Create(*result);
isolate->global_handles()->MakeWeak(handle.location(), NULL,
&ClearWrapperCache);
- script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
+ script->wrapper()->set_address(reinterpret_cast<Address>(handle.location()));
return result;
}
diff --git a/src/heap.cc b/src/heap.cc
index 907ba6b..5dca592 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1730,10 +1730,10 @@
}
set_heap_number_map(Map::cast(obj));
- { MaybeObject* maybe_obj = AllocateMap(PROXY_TYPE, Proxy::kSize);
+ { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
- set_proxy_map(Map::cast(obj));
+ set_foreign_map(Map::cast(obj));
for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
const StringTypeTable& entry = string_type_table[i];
@@ -2118,12 +2118,12 @@
}
hidden_symbol_ = String::cast(obj);
- // Allocate the proxy for __proto__.
+ // Allocate the foreign for __proto__.
{ MaybeObject* maybe_obj =
- AllocateProxy((Address) &Accessors::ObjectPrototype);
+ AllocateForeign((Address) &Accessors::ObjectPrototype);
if (!maybe_obj->ToObject(&obj)) return false;
}
- set_prototype_accessors(Proxy::cast(obj));
+ set_prototype_accessors(Foreign::cast(obj));
// Allocate the code_stubs dictionary. The initial size is set to avoid
// expanding the dictionary during bootstrapping.
@@ -2341,16 +2341,16 @@
}
-MaybeObject* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
- // Statically ensure that it is safe to allocate proxies in paged spaces.
- STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
+MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
+ // Statically ensure that it is safe to allocate foreigns in paged spaces.
+ STATIC_ASSERT(Foreign::kSize <= Page::kMaxHeapObjectSize);
AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
Object* result;
- { MaybeObject* maybe_result = Allocate(proxy_map(), space);
+ { MaybeObject* maybe_result = Allocate(foreign_map(), space);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Proxy::cast(result)->set_proxy(proxy);
+ Foreign::cast(result)->set_address(address);
return result;
}
diff --git a/src/heap.h b/src/heap.h
index 6c29a0a..012e1bc 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1,4 +1,4 @@
-// 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:
@@ -112,12 +112,12 @@
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
V(Map, shared_function_info_map, SharedFunctionInfoMap) \
V(Map, message_object_map, JSMessageObjectMap) \
- V(Map, proxy_map, ProxyMap) \
+ V(Map, foreign_map, ForeignMap) \
V(Object, nan_value, NanValue) \
V(Object, minus_zero_value, MinusZeroValue) \
V(Map, neander_map, NeanderMap) \
V(JSObject, message_listeners, MessageListeners) \
- V(Proxy, prototype_accessors, PrototypeAccessors) \
+ V(Foreign, prototype_accessors, PrototypeAccessors) \
V(NumberDictionary, code_stubs, CodeStubs) \
V(NumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(Code, js_entry_code, JsEntryCode) \
@@ -178,8 +178,14 @@
V(value_of_symbol, "valueOf") \
V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \
V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \
- V(KeyedLoadSpecialized_symbol, "KeyedLoadSpecialized") \
- V(KeyedStoreSpecialized_symbol, "KeyedStoreSpecialized") \
+ V(KeyedLoadSpecializedMonomorphic_symbol, \
+ "KeyedLoadSpecializedMonomorphic") \
+ V(KeyedLoadSpecializedPolymorphic_symbol, \
+ "KeyedLoadSpecializedPolymorphic") \
+ V(KeyedStoreSpecializedMonomorphic_symbol, \
+ "KeyedStoreSpecializedMonomorphic") \
+ V(KeyedStoreSpecializedPolymorphic_symbol, \
+ "KeyedStoreSpecializedPolymorphic") \
V(stack_overflow_symbol, "kStackOverflowBoilerplate") \
V(illegal_access_symbol, "illegal access") \
V(out_of_memory_symbol, "out-of-memory") \
@@ -207,32 +213,7 @@
V(global_eval_symbol, "GlobalEval") \
V(identity_hash_symbol, "v8::IdentityHash") \
V(closure_symbol, "(closure)") \
- V(use_strict, "use strict") \
- V(KeyedLoadExternalByteArray_symbol, "KeyedLoadExternalByteArray") \
- V(KeyedLoadExternalUnsignedByteArray_symbol, \
- "KeyedLoadExternalUnsignedByteArray") \
- V(KeyedLoadExternalShortArray_symbol, \
- "KeyedLoadExternalShortArray") \
- V(KeyedLoadExternalUnsignedShortArray_symbol, \
- "KeyedLoadExternalUnsignedShortArray") \
- V(KeyedLoadExternalIntArray_symbol, "KeyedLoadExternalIntArray") \
- V(KeyedLoadExternalUnsignedIntArray_symbol, \
- "KeyedLoadExternalUnsignedIntArray") \
- V(KeyedLoadExternalFloatArray_symbol, "KeyedLoadExternalFloatArray") \
- V(KeyedLoadExternalDoubleArray_symbol, "KeyedLoadExternalDoubleArray") \
- V(KeyedLoadExternalPixelArray_symbol, "KeyedLoadExternalPixelArray") \
- V(KeyedStoreExternalByteArray_symbol, "KeyedStoreExternalByteArray") \
- V(KeyedStoreExternalUnsignedByteArray_symbol, \
- "KeyedStoreExternalUnsignedByteArray") \
- V(KeyedStoreExternalShortArray_symbol, "KeyedStoreExternalShortArray") \
- V(KeyedStoreExternalUnsignedShortArray_symbol, \
- "KeyedStoreExternalUnsignedShortArray") \
- V(KeyedStoreExternalIntArray_symbol, "KeyedStoreExternalIntArray") \
- V(KeyedStoreExternalUnsignedIntArray_symbol, \
- "KeyedStoreExternalUnsignedIntArray") \
- V(KeyedStoreExternalFloatArray_symbol, "KeyedStoreExternalFloatArray") \
- V(KeyedStoreExternalDoubleArray_symbol, "KeyedStoreExternalDoubleArray") \
- V(KeyedStoreExternalPixelArray_symbol, "KeyedStoreExternalPixelArray")
+ V(use_strict, "use strict")
// Forward declarations.
class GCTracer;
@@ -707,12 +688,12 @@
// Please note this does not perform a garbage collection.
MUST_USE_RESULT inline MaybeObject* NumberFromUint32(uint32_t value);
- // Allocates a new proxy object.
+ // Allocates a new foreign object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT MaybeObject* AllocateProxy(
- Address proxy, PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateForeign(
+ Address address, PretenureFlag pretenure = NOT_TENURED);
// Allocates a new SharedFunctionInfo object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 35981ae..32ff28b 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -521,6 +521,22 @@
return GetConstant(&constant_false_, isolate()->heap()->false_value());
}
+HGraphBuilder::HGraphBuilder(CompilationInfo* info,
+ TypeFeedbackOracle* oracle)
+ : function_state_(NULL),
+ initial_function_state_(this, info, oracle),
+ ast_context_(NULL),
+ break_scope_(NULL),
+ graph_(NULL),
+ current_block_(NULL),
+ inlined_count_(0),
+ zone_(info->isolate()->zone()),
+ inline_bailout_(false) {
+ // This is not initialized in the initializer list because the
+ // constructor for the initial state relies on function_state_ == NULL
+ // to know it's the initial state.
+ function_state_= &initial_function_state_;
+}
HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first,
HBasicBlock* second,
@@ -1021,13 +1037,13 @@
}
-HValueMap::HValueMap(const HValueMap* other)
+HValueMap::HValueMap(Zone* zone, const HValueMap* other)
: array_size_(other->array_size_),
lists_size_(other->lists_size_),
count_(other->count_),
present_flags_(other->present_flags_),
- array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)),
- lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)),
+ array_(zone->NewArray<HValueMapListElement>(other->array_size_)),
+ lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)),
free_list_head_(other->free_list_head_) {
memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
@@ -1240,13 +1256,49 @@
}
+// Simple sparse set with O(1) add, contains, and clear.
+class SparseSet {
+ public:
+ SparseSet(Zone* zone, int capacity)
+ : capacity_(capacity),
+ length_(0),
+ dense_(zone->NewArray<int>(capacity)),
+ sparse_(zone->NewArray<int>(capacity)) {}
+
+ bool Contains(int n) const {
+ ASSERT(0 <= n && n < capacity_);
+ int d = sparse_[n];
+ return 0 <= d && d < length_ && dense_[d] == n;
+ }
+
+ bool Add(int n) {
+ if (Contains(n)) return false;
+ dense_[length_] = n;
+ sparse_[n] = length_;
+ ++length_;
+ return true;
+ }
+
+ void Clear() { length_ = 0; }
+
+ private:
+ int capacity_;
+ int length_;
+ int* dense_;
+ int* sparse_;
+
+ DISALLOW_COPY_AND_ASSIGN(SparseSet);
+};
+
+
class HGlobalValueNumberer BASE_EMBEDDED {
public:
explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info)
: graph_(graph),
info_(info),
- block_side_effects_(graph_->blocks()->length()),
- loop_side_effects_(graph_->blocks()->length()) {
+ block_side_effects_(graph->blocks()->length()),
+ loop_side_effects_(graph->blocks()->length()),
+ visited_on_paths_(graph->zone(), graph->blocks()->length()) {
ASSERT(info->isolate()->heap()->allow_allocation(false));
block_side_effects_.AddBlock(0, graph_->blocks()->length());
loop_side_effects_.AddBlock(0, graph_->blocks()->length());
@@ -1258,6 +1310,8 @@
void Analyze();
private:
+ int CollectSideEffectsOnPathsToDominatedBlock(HBasicBlock* dominator,
+ HBasicBlock* dominated);
void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
void ComputeBlockSideEffects();
void LoopInvariantCodeMotion();
@@ -1279,6 +1333,10 @@
// A map of loop header block IDs to their loop's side effects.
ZoneList<int> loop_side_effects_;
+
+ // Used when collecting side effects on paths from dominator to
+ // dominated.
+ SparseSet visited_on_paths_;
};
@@ -1414,8 +1472,27 @@
}
+int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
+ HBasicBlock* dominator, HBasicBlock* dominated) {
+ int side_effects = 0;
+ for (int i = 0; i < dominated->predecessors()->length(); ++i) {
+ HBasicBlock* block = dominated->predecessors()->at(i);
+ if (dominator->block_id() < block->block_id() &&
+ block->block_id() < dominated->block_id() &&
+ visited_on_paths_.Add(block->block_id())) {
+ side_effects |= block_side_effects_[block->block_id()];
+ side_effects |= CollectSideEffectsOnPathsToDominatedBlock(
+ dominator, block);
+ }
+ }
+ return side_effects;
+}
+
+
void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
- TraceGVN("Analyzing block B%d\n", block->block_id());
+ TraceGVN("Analyzing block B%d%s\n",
+ block->block_id(),
+ block->IsLoopHeader() ? " (loop header)" : "");
// If this is a loop header kill everything killed by the loop.
if (block->IsLoopHeader()) {
@@ -1456,23 +1533,18 @@
// No need to copy the map for the last child in the dominator tree.
HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone());
- // If the dominated block is not a successor to this block we have to
- // kill everything killed on any path between this block and the
- // dominated block. Note we rely on the block ordering.
- bool is_successor = false;
- int predecessor_count = dominated->predecessors()->length();
- for (int j = 0; !is_successor && j < predecessor_count; ++j) {
- is_successor = (dominated->predecessors()->at(j) == block);
+ // Kill everything killed on any path between this block and the
+ // dominated block.
+ // We don't have to traverse these paths if the value map is
+ // already empty.
+ // If the range of block ids (block_id, dominated_id) is empty
+ // there are no such paths.
+ if (!successor_map->IsEmpty() &&
+ block->block_id() + 1 < dominated->block_id()) {
+ visited_on_paths_.Clear();
+ successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block,
+ dominated));
}
-
- if (!is_successor) {
- int side_effects = 0;
- for (int j = block->block_id() + 1; j < dominated->block_id(); ++j) {
- side_effects |= block_side_effects_[j];
- }
- successor_map->Kill(side_effects);
- }
-
AnalyzeBlock(dominated, successor_map);
}
}
@@ -3963,22 +4035,17 @@
}
-void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) {
+void HGraphBuilder::TraceInline(Handle<JSFunction> target,
+ Handle<JSFunction> caller,
+ const char* reason) {
if (FLAG_trace_inlining) {
+ SmartPointer<char> target_name = target->shared()->DebugName()->ToCString();
+ SmartPointer<char> caller_name = caller->shared()->DebugName()->ToCString();
if (reason == NULL) {
- // We are currently in the context of inlined function thus we have
- // to go to an outer FunctionState to get caller.
- SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
- SmartPointer<char> caller =
- function_state()->outer()->compilation_info()->function()->
- debug_name()->ToCString();
- PrintF("Inlined %s called from %s.\n", *callee, *caller);
+ PrintF("Inlined %s called from %s.\n", *target_name, *caller_name);
} else {
- SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
- SmartPointer<char> caller =
- info()->function()->debug_name()->ToCString();
PrintF("Did not inline %s called from %s (%s).\n",
- *callee, *caller, reason);
+ *target_name, *caller_name, reason);
}
}
}
@@ -3989,18 +4056,20 @@
// Precondition: call is monomorphic and we have found a target with the
// appropriate arity.
+ Handle<JSFunction> caller = info()->closure();
Handle<JSFunction> target = expr->target();
+ Handle<SharedFunctionInfo> target_shared(target->shared());
// Do a quick check on source code length to avoid parsing large
// inlining candidates.
if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) {
- TraceInline(target, "target text too big");
+ TraceInline(target, caller, "target text too big");
return false;
}
// Target must be inlineable.
if (!target->IsInlineable()) {
- TraceInline(target, "target not inlineable");
+ TraceInline(target, caller, "target not inlineable");
return false;
}
@@ -4009,7 +4078,7 @@
if (target->context() != outer_info->closure()->context() ||
outer_info->scope()->contains_with() ||
outer_info->scope()->num_heap_slots() > 0) {
- TraceInline(target, "target requires context change");
+ TraceInline(target, caller, "target requires context change");
return false;
}
@@ -4018,7 +4087,7 @@
int current_level = 1;
while (env->outer() != NULL) {
if (current_level == Compiler::kMaxInliningLevels) {
- TraceInline(target, "inline depth limit reached");
+ TraceInline(target, caller, "inline depth limit reached");
return false;
}
current_level++;
@@ -4026,14 +4095,14 @@
}
// Don't inline recursive functions.
- if (target->shared() == outer_info->closure()->shared()) {
- TraceInline(target, "target is recursive");
+ if (*target_shared == outer_info->closure()->shared()) {
+ TraceInline(target, caller, "target is recursive");
return false;
}
// We don't want to add more than a certain number of nodes from inlining.
if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) {
- TraceInline(target, "cumulative AST node limit reached");
+ TraceInline(target, caller, "cumulative AST node limit reached");
return false;
}
@@ -4046,14 +4115,14 @@
if (target_info.isolate()->has_pending_exception()) {
// Parse or scope error, never optimize this function.
SetStackOverflow();
- target->shared()->set_optimization_disabled(true);
+ target_shared->DisableOptimization(*target);
}
- TraceInline(target, "parse failure");
+ TraceInline(target, caller, "parse failure");
return false;
}
if (target_info.scope()->num_heap_slots() > 0) {
- TraceInline(target, "target has context-allocated variables");
+ TraceInline(target, caller, "target has context-allocated variables");
return false;
}
FunctionLiteral* function = target_info.function();
@@ -4061,32 +4130,31 @@
// Count the number of AST nodes added by inlining this call.
int nodes_added = AstNode::Count() - count_before;
if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) {
- TraceInline(target, "target AST is too large");
+ TraceInline(target, caller, "target AST is too large");
return false;
}
// Check if we can handle all declarations in the inlined functions.
VisitDeclarations(target_info.scope()->declarations());
if (HasStackOverflow()) {
- TraceInline(target, "target has non-trivial declaration");
+ TraceInline(target, caller, "target has non-trivial declaration");
ClearStackOverflow();
return false;
}
// Don't inline functions that uses the arguments object or that
// have a mismatching number of parameters.
- Handle<SharedFunctionInfo> target_shared(target->shared());
int arity = expr->arguments()->length();
if (function->scope()->arguments() != NULL ||
arity != target_shared->formal_parameter_count()) {
- TraceInline(target, "target requires special argument handling");
+ TraceInline(target, caller, "target requires special argument handling");
return false;
}
// All statements in the body must be inlineable.
for (int i = 0, count = function->body()->length(); i < count; ++i) {
if (!function->body()->at(i)->IsInlineable()) {
- TraceInline(target, "target contains unsupported syntax");
+ TraceInline(target, caller, "target contains unsupported syntax");
return false;
}
}
@@ -4098,7 +4166,7 @@
// generating the optimized inline code.
target_info.EnableDeoptimizationSupport();
if (!FullCodeGenerator::MakeCode(&target_info)) {
- TraceInline(target, "could not generate deoptimization info");
+ TraceInline(target, caller, "could not generate deoptimization info");
return false;
}
target_shared->EnableDeoptimizationSupport(*target_info.code());
@@ -4132,14 +4200,16 @@
if (HasStackOverflow()) {
// Bail out if the inline function did, as we cannot residualize a call
// instead.
- TraceInline(target, "inline graph construction failed");
+ TraceInline(target, caller, "inline graph construction failed");
+ target_shared->DisableOptimization(*target);
+ inline_bailout_ = true;
return true;
}
// Update inlined nodes count.
inlined_count_ += nodes_added;
- TraceInline(target, NULL);
+ TraceInline(target, caller, NULL);
if (current_block() != NULL) {
// Add a return of undefined if control can fall off the body. In a
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 41ae0be..1827d87 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -660,20 +660,7 @@
BreakAndContinueScope* next_;
};
- HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle)
- : function_state_(NULL),
- initial_function_state_(this, info, oracle),
- ast_context_(NULL),
- break_scope_(NULL),
- graph_(NULL),
- current_block_(NULL),
- inlined_count_(0),
- zone_(info->isolate()->zone()) {
- // This is not initialized in the initializer list because the
- // constructor for the initial state relies on function_state_ == NULL
- // to know it's the initial state.
- function_state_= &initial_function_state_;
- }
+ HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
HGraph* CreateGraph();
@@ -688,6 +675,8 @@
return current_block()->last_environment();
}
+ bool inline_bailout() { return inline_bailout_; }
+
// Adding instructions.
HInstruction* AddInstruction(HInstruction* instr);
void AddSimulate(int id);
@@ -857,7 +846,9 @@
// If --trace-inlining, print a line of the inlining trace. Inlining
// succeeded if the reason string is NULL and failed if there is a
// non-NULL reason string.
- void TraceInline(Handle<JSFunction> target, const char* failure_reason);
+ void TraceInline(Handle<JSFunction> target,
+ Handle<JSFunction> caller,
+ const char* failure_reason);
void HandleGlobalVariableAssignment(Variable* var,
HValue* value,
@@ -974,6 +965,8 @@
Zone* zone_;
+ bool inline_bailout_;
+
friend class FunctionState; // Pushes and pops the state stack.
friend class AstContext; // Pushes and pops the AST context stack.
@@ -1008,9 +1001,11 @@
HValue* Lookup(HValue* value) const;
HValueMap* Copy(Zone* zone) const {
- return new(zone) HValueMap(this);
+ return new(zone) HValueMap(zone, this);
}
+ bool IsEmpty() const { return count_ == 0; }
+
private:
// A linked list of HValue* values. Stored in arrays.
struct HValueMapListElement {
@@ -1022,7 +1017,7 @@
// Must be a power of 2.
static const int kInitialSize = 16;
- explicit HValueMap(const HValueMap* other);
+ HValueMap(Zone* zone, const HValueMap* other);
void Resize(int new_size);
void ResizeLists(int new_size);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 534c187..ac0b645 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -244,9 +244,25 @@
void ToBooleanStub::Generate(MacroAssembler* masm) {
Label false_result, true_result, not_string;
__ mov(eax, Operand(esp, 1 * kPointerSize));
+ Factory* factory = masm->isolate()->factory();
+
+ // undefined -> false
+ __ cmp(eax, factory->undefined_value());
+ __ j(equal, &false_result);
+
+ // Boolean -> its value
+ __ cmp(eax, factory->true_value());
+ __ j(equal, &true_result);
+ __ cmp(eax, factory->false_value());
+ __ j(equal, &false_result);
+
+ // Smis: 0 -> false, all other -> true
+ __ test(eax, Operand(eax));
+ __ j(zero, &false_result);
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &true_result);
// 'null' => false.
- Factory* factory = masm->isolate()->factory();
__ cmp(eax, factory->null_value());
__ j(equal, &false_result, Label::kNear);
@@ -606,10 +622,13 @@
}
-void TypeRecordingUnaryOpStub::GenerateSmiCodeSub(
- MacroAssembler* masm, Label* non_smi, Label* undo, Label* slow,
- Label::Distance non_smi_near, Label::Distance undo_near,
- Label::Distance slow_near) {
+void TypeRecordingUnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
+ Label* non_smi,
+ Label* undo,
+ Label* slow,
+ Label::Distance non_smi_near,
+ Label::Distance undo_near,
+ Label::Distance slow_near) {
// Check whether the value is a smi.
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, non_smi, non_smi_near);
@@ -663,14 +682,16 @@
void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
- Label non_smi, undo, slow;
- GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear);
+ Label non_smi, undo, slow, call_builtin;
+ GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear);
__ bind(&non_smi);
GenerateHeapNumberCodeSub(masm, &slow);
__ bind(&undo);
GenerateSmiCodeUndo(masm);
__ bind(&slow);
GenerateTypeTransition(masm);
+ __ bind(&call_builtin);
+ GenerateGenericCodeFallback(masm);
}
@@ -1067,7 +1088,7 @@
// Smi tagging these two cases can only happen with shifts
// by 0 or 1 when handed a valid smi.
__ test(left, Immediate(0xc0000000));
- __ j(not_zero, slow);
+ __ j(not_zero, &use_fp_on_smis);
// Tag the result and store it in register eax.
__ SmiTag(left);
__ mov(eax, left);
@@ -1203,26 +1224,35 @@
} else {
ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS);
switch (op_) {
- case Token::SHL: {
+ case Token::SHL:
+ case Token::SHR: {
Comment perform_float(masm, "-- Perform float operation on smis");
__ bind(&use_fp_on_smis);
// Result we want is in left == edx, so we can put the allocated heap
// number in eax.
__ AllocateHeapNumber(eax, ecx, ebx, slow);
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
- CpuFeatures::Scope use_sse2(SSE2);
- __ cvtsi2sd(xmm0, Operand(left));
- __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
- } else {
- // It's OK to overwrite the right argument on the stack because we
- // are about to return.
+ // It's OK to overwrite the arguments on the stack because we
+ // are about to return.
+ if (op_ == Token::SHR) {
__ mov(Operand(esp, 1 * kPointerSize), left);
- __ fild_s(Operand(esp, 1 * kPointerSize));
+ __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
+ __ fild_d(Operand(esp, 1 * kPointerSize));
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ } else {
+ ASSERT_EQ(Token::SHL, op_);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope use_sse2(SSE2);
+ __ cvtsi2sd(xmm0, Operand(left));
+ __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
+ } else {
+ __ mov(Operand(esp, 1 * kPointerSize), left);
+ __ fild_s(Operand(esp, 1 * kPointerSize));
+ __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ }
}
- __ ret(2 * kPointerSize);
- break;
+ __ ret(2 * kPointerSize);
+ break;
}
case Token::ADD:
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 59c3373..d20e622 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -548,25 +548,10 @@
void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
- // Emit the inlined tests assumed by the stub.
- __ cmp(result_register(), isolate()->factory()->undefined_value());
- __ j(equal, if_false);
- __ cmp(result_register(), isolate()->factory()->true_value());
- __ j(equal, if_true);
- __ cmp(result_register(), isolate()->factory()->false_value());
- __ j(equal, if_false);
- STATIC_ASSERT(kSmiTag == 0);
- __ test(result_register(), Operand(result_register()));
- __ j(zero, if_false);
- __ test(result_register(), Immediate(kSmiTagMask));
- __ j(zero, if_true);
-
- // Call the ToBoolean stub for all other cases.
ToBooleanStub stub;
__ push(result_register());
__ CallStub(&stub);
__ test(eax, Operand(eax));
-
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
}
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index bde3b7e..090ea40 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -655,7 +655,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
@@ -698,7 +698,7 @@
__ TailCallExternalReference(ref, 2, 1);
__ bind(&slow);
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
@@ -1222,7 +1222,7 @@
}
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -1237,8 +1237,10 @@
__ push(ebx); // return address
// Perform tail call to the entry.
- ExternalReference ref =
- ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
+ ExternalReference ref = force_generic
+ ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
+ masm->isolate())
+ : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1430,7 +1432,7 @@
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -1445,8 +1447,30 @@
__ push(ebx);
// Do tail-call to runtime routine.
- ExternalReference ref =
- ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
+ ExternalReference ref = force_generic
+ ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
+ masm->isolate())
+ : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
+ __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+
+ __ pop(ebx);
+ __ push(edx);
+ __ push(ecx);
+ __ push(eax);
+ __ push(ebx); // return address
+
+ // Do tail-call to runtime routine.
+ ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 76eaec5..3ca3c9f 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1046,116 +1046,102 @@
LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HValue* v = instr->value();
- if (v->EmitAtUses()) {
- if (v->IsClassOfTest()) {
- HClassOfTest* compare = HClassOfTest::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
- TempRegister(),
- TempRegister());
- } else if (v->IsCompare()) {
- HCompare* compare = HCompare::cast(v);
- Token::Value op = compare->token();
- HValue* left = compare->left();
- HValue* right = compare->right();
- Representation r = compare->GetInputRepresentation();
- if (r.IsInteger32()) {
- ASSERT(left->representation().IsInteger32());
- ASSERT(right->representation().IsInteger32());
-
- return new LCmpIDAndBranch(UseRegisterAtStart(left),
- UseOrConstantAtStart(right));
- } else if (r.IsDouble()) {
- ASSERT(left->representation().IsDouble());
- ASSERT(right->representation().IsDouble());
-
- return new LCmpIDAndBranch(UseRegisterAtStart(left),
- UseRegisterAtStart(right));
- } else {
- ASSERT(left->representation().IsTagged());
- ASSERT(right->representation().IsTagged());
- bool reversed = op == Token::GT || op == Token::LTE;
- LOperand* left_operand = UseFixed(left, reversed ? eax : edx);
- LOperand* right_operand = UseFixed(right, reversed ? edx : eax);
- LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
- right_operand);
- return MarkAsCall(result, instr);
- }
- } else if (v->IsIsSmi()) {
- HIsSmi* compare = HIsSmi::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsSmiAndBranch(Use(compare->value()));
- } else if (v->IsIsUndetectable()) {
- HIsUndetectable* compare = HIsUndetectable::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
- TempRegister());
- } else if (v->IsHasInstanceType()) {
- HHasInstanceType* compare = HHasInstanceType::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
- TempRegister());
- } else if (v->IsHasCachedArrayIndex()) {
- HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LHasCachedArrayIndexAndBranch(
- UseRegisterAtStart(compare->value()));
- } else if (v->IsIsNull()) {
- HIsNull* compare = HIsNull::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- // We only need a temp register for non-strict compare.
- LOperand* temp = compare->is_strict() ? NULL : TempRegister();
- return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
- temp);
- } else if (v->IsIsObject()) {
- HIsObject* compare = HIsObject::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- LOperand* temp1 = TempRegister();
- LOperand* temp2 = TempRegister();
- return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
- temp1,
- temp2);
- } else if (v->IsCompareJSObjectEq()) {
- HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
- return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
- UseRegisterAtStart(compare->right()));
- } else if (v->IsCompareSymbolEq()) {
- HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
- return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
- UseRegisterAtStart(compare->right()));
- } else if (v->IsInstanceOf()) {
- HInstanceOf* instance_of = HInstanceOf::cast(v);
- LOperand* left = UseFixed(instance_of->left(), InstanceofStub::left());
- LOperand* right = UseFixed(instance_of->right(), InstanceofStub::right());
- LOperand* context = UseFixed(instance_of->context(), esi);
- LInstanceOfAndBranch* result =
- new LInstanceOfAndBranch(context, left, right);
- return MarkAsCall(result, instr);
- } else if (v->IsTypeofIs()) {
- HTypeofIs* typeof_is = HTypeofIs::cast(v);
- return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
- } else if (v->IsIsConstructCall()) {
- return new LIsConstructCallAndBranch(TempRegister());
+ if (!v->EmitAtUses()) {
+ return new LBranch(UseRegisterAtStart(v));
+ } else if (v->IsClassOfTest()) {
+ HClassOfTest* compare = HClassOfTest::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
+ TempRegister(),
+ TempRegister());
+ } else if (v->IsCompare()) {
+ HCompare* compare = HCompare::cast(v);
+ Token::Value op = compare->token();
+ HValue* left = compare->left();
+ HValue* right = compare->right();
+ Representation r = compare->GetInputRepresentation();
+ if (r.IsInteger32()) {
+ ASSERT(left->representation().IsInteger32());
+ ASSERT(right->representation().IsInteger32());
+ return new LCmpIDAndBranch(UseRegisterAtStart(left),
+ UseOrConstantAtStart(right));
+ } else if (r.IsDouble()) {
+ ASSERT(left->representation().IsDouble());
+ ASSERT(right->representation().IsDouble());
+ return new LCmpIDAndBranch(UseRegisterAtStart(left),
+ UseRegisterAtStart(right));
} else {
- if (v->IsConstant()) {
- if (HConstant::cast(v)->ToBoolean()) {
- return new LGoto(instr->FirstSuccessor()->block_id());
- } else {
- return new LGoto(instr->SecondSuccessor()->block_id());
- }
- }
- Abort("Undefined compare before branch");
- return NULL;
+ ASSERT(left->representation().IsTagged());
+ ASSERT(right->representation().IsTagged());
+ bool reversed = op == Token::GT || op == Token::LTE;
+ LOperand* left_operand = UseFixed(left, reversed ? eax : edx);
+ LOperand* right_operand = UseFixed(right, reversed ? edx : eax);
+ LCmpTAndBranch* result = new LCmpTAndBranch(left_operand, right_operand);
+ return MarkAsCall(result, instr);
}
+ } else if (v->IsIsSmi()) {
+ HIsSmi* compare = HIsSmi::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsSmiAndBranch(Use(compare->value()));
+ } else if (v->IsIsUndetectable()) {
+ HIsUndetectable* compare = HIsUndetectable::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
+ TempRegister());
+ } else if (v->IsHasInstanceType()) {
+ HHasInstanceType* compare = HHasInstanceType::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
+ TempRegister());
+ } else if (v->IsHasCachedArrayIndex()) {
+ HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LHasCachedArrayIndexAndBranch(
+ UseRegisterAtStart(compare->value()));
+ } else if (v->IsIsNull()) {
+ HIsNull* compare = HIsNull::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ // We only need a temp register for non-strict compare.
+ LOperand* temp = compare->is_strict() ? NULL : TempRegister();
+ return new LIsNullAndBranch(UseRegisterAtStart(compare->value()), temp);
+ } else if (v->IsIsObject()) {
+ HIsObject* compare = HIsObject::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
+ temp1,
+ temp2);
+ } else if (v->IsCompareJSObjectEq()) {
+ HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
+ return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
+ UseRegisterAtStart(compare->right()));
+ } else if (v->IsCompareSymbolEq()) {
+ HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
+ return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
+ UseRegisterAtStart(compare->right()));
+ } else if (v->IsInstanceOf()) {
+ HInstanceOf* instance_of = HInstanceOf::cast(v);
+ LOperand* left = UseFixed(instance_of->left(), InstanceofStub::left());
+ LOperand* right = UseFixed(instance_of->right(), InstanceofStub::right());
+ LOperand* context = UseFixed(instance_of->context(), esi);
+ LInstanceOfAndBranch* result =
+ new LInstanceOfAndBranch(context, left, right);
+ return MarkAsCall(result, instr);
+ } else if (v->IsTypeofIs()) {
+ HTypeofIs* typeof_is = HTypeofIs::cast(v);
+ return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+ } else if (v->IsIsConstructCall()) {
+ return new LIsConstructCallAndBranch(TempRegister());
+ } else if (v->IsConstant()) {
+ HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
+ ? instr->FirstSuccessor()
+ : instr->SecondSuccessor();
+ return new LGoto(successor->block_id());
+ } else {
+ Abort("Undefined compare before branch");
+ return NULL;
}
- return new LBranch(UseRegisterAtStart(v));
}
@@ -2016,7 +2002,6 @@
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
- LOperand* temp = NULL;
LOperand* val = NULL;
if (array_type == kExternalByteArray ||
array_type == kExternalUnsignedByteArray) {
@@ -2028,8 +2013,7 @@
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
- val,
- temp);
+ val);
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 13139ea..694ede8 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1813,16 +1813,14 @@
};
-class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 1> {
+class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key,
- LOperand* val,
- LOperand* temp) {
+ LOperand* val) {
inputs_[0] = external_pointer;
inputs_[1] = key;
inputs_[2] = val;
- temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 7b2f6cf..f38e2ee 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -286,6 +286,21 @@
}
+void MacroAssembler::DispatchMap(Register obj,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type) {
+ Label fail;
+ if (smi_check_type == DONT_DO_SMI_CHECK) {
+ JumpIfSmi(obj, &fail);
+ }
+ cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
+ j(equal, success);
+
+ bind(&fail);
+}
+
+
Condition MacroAssembler::IsObjectStringType(Register heap_object,
Register map,
Register instance_type) {
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index f48ed13..837e981 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -45,6 +45,7 @@
RESULT_CONTAINS_TOP = 1 << 1
};
+
// Convenience for platform-independent signatures. We do not normally
// distinguish memory operands from other operands on ia32.
typedef Operand MemOperand;
@@ -206,14 +207,22 @@
// Compare instance type for map.
void CmpInstanceType(Register map, InstanceType type);
- // Check if the map of an object is equal to a specified map and
- // branch to label if not. Skip the smi check if not required
- // (object is known to be a heap object)
+ // Check if the map of an object is equal to a specified map and branch to
+ // label if not. Skip the smi check if not required (object is known to be a
+ // heap object)
void CheckMap(Register obj,
Handle<Map> map,
Label* fail,
SmiCheckType smi_check_type);
+ // Check if the map of an object is equal to a specified map and branch to a
+ // specified target if equal. Skip the smi check if not required (object is
+ // known to be a heap object)
+ void DispatchMap(Register obj,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type);
+
// Check if the object in register heap_object is a string. Afterwards the
// register map contains the object map and the register instance_type
// contains the instance_type. The registers map and instance_type can be the
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 3379ff0..c9c22d2 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -713,6 +713,14 @@
}
+void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
+ Code* code = masm->isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_MissForceGeneric);
+ Handle<Code> ic(code);
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+}
+
+
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
@@ -2115,6 +2123,7 @@
// repatch it to global receiver.
if (object->IsGlobalObject()) return heap()->undefined_value();
if (cell != NULL) return heap()->undefined_value();
+ if (!object->IsJSObject()) return heap()->undefined_value();
int depth = optimization.GetPrototypeDepthOfExpectedType(
JSObject::cast(object), holder);
if (depth == kInvalidProtoDepth) return heap()->undefined_value();
@@ -2654,8 +2663,35 @@
}
-MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
- JSObject* receiver) {
+MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement(
+ Map* receiver_map) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ MaybeObject* maybe_stub =
+ KeyedStoreFastElementStub(is_js_array).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(edx,
+ Handle<Map>(receiver_map),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL);
+}
+
+
+MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -2663,51 +2699,22 @@
// -- esp[0] : return address
// -----------------------------------
Label miss;
+ __ JumpIfSmi(edx, &miss);
- // Check that the receiver isn't a smi.
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &miss);
-
- // Check that the map matches.
- __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- Immediate(Handle<Map>(receiver->map())));
- __ j(not_equal, &miss);
-
- // Check that the key is a smi.
- __ test(ecx, Immediate(kSmiTagMask));
- __ j(not_zero, &miss);
-
- // Get the elements array and make sure it is a fast element array, not 'cow'.
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
- __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
- Immediate(factory()->fixed_array_map()));
- __ j(not_equal, &miss);
-
- // Check that the key is within bounds.
- if (receiver->IsJSArray()) {
- __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
- __ j(above_equal, &miss);
- } else {
- __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // Compare smis.
- __ j(above_equal, &miss);
+ Register map_reg = ebx;
+ __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
+ int receiver_count = receiver_maps->length();
+ for (int current = 0; current < receiver_count; ++current) {
+ Handle<Map> map(receiver_maps->at(current));
+ __ cmp(map_reg, map);
+ __ j(equal, Handle<Code>(handler_ics->at(current)));
}
-
- // Do the store and update the write barrier. Make sure to preserve
- // the value in register eax.
- __ mov(edx, Operand(eax));
- __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
- __ RecordWrite(edi, 0, edx, ecx);
-
- // Done.
- __ ret(0);
-
- // Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
- __ jmp(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ jmp(miss_ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@@ -3120,48 +3127,52 @@
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
+ // ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(edx,
+ Handle<Map>(receiver_map),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
+ __ JumpIfSmi(edx, &miss);
- // Check that the receiver isn't a smi.
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &miss);
-
- // Check that the map matches.
- __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- Immediate(Handle<Map>(receiver->map())));
- __ j(not_equal, &miss);
-
- // Check that the key is a smi.
- __ test(eax, Immediate(kSmiTagMask));
- __ j(not_zero, &miss);
-
- // Get the elements array.
- __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
- __ AssertFastElements(ecx);
-
- // Check that the key is within bounds.
- __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
- __ j(above_equal, &miss);
-
- // Load the result and make sure it's not the hole.
- __ mov(ebx, Operand(ecx, eax, times_2,
- FixedArray::kHeaderSize - kHeapObjectTag));
- __ cmp(ebx, factory()->the_hole_value());
- __ j(equal, &miss);
- __ mov(eax, ebx);
- __ ret(0);
+ Register map_reg = ebx;
+ __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
+ int receiver_count = receiver_maps->length();
+ for (int current = 0; current < receiver_count; ++current) {
+ Handle<Map> map(receiver_maps->at(current));
+ __ cmp(map_reg, map);
+ __ j(equal, Handle<Code>(handler_ics->at(current)));
+ }
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@@ -3304,36 +3315,82 @@
}
-MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) {
+MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad(
+ JSObject*receiver, ExternalArrayType array_type) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- Label slow, failed_allocation;
+ MaybeObject* maybe_stub =
+ KeyedLoadExternalArrayStub(array_type).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(edx,
+ Handle<Map>(receiver->map()),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
- // Check that the object isn't a smi.
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &slow);
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode();
+}
+
+
+MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
+ JSObject* receiver, ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ MaybeObject* maybe_stub =
+ KeyedStoreExternalArrayStub(array_type).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(edx,
+ Handle<Map>(receiver->map()),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ return GetCode();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void KeyedLoadStubCompiler::GenerateLoadExternalArray(
+ MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss_force_generic, failed_allocation, slow;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ test(eax, Immediate(kSmiTagMask));
- __ j(not_zero, &slow);
+ __ j(not_zero, &miss_force_generic);
- // Check that the map matches.
- __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
-
- // eax: key, known to be a smi.
- // edx: receiver, known to be a JSObject.
- // ebx: elements object, known to be an external array.
// Check that the index is in range.
__ mov(ecx, eax);
__ SmiUntag(ecx); // Untag the index.
+ __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
- __ j(above_equal, &slow);
+ __ j(above_equal, &miss_force_generic);
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (array_type) {
@@ -3440,47 +3497,48 @@
// Slow case: Jump to runtime.
__ bind(&slow);
- Counters* counters = isolate()->counters();
+ Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
+
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- __ pop(ebx);
- __ push(edx); // receiver
- __ push(eax); // name
- __ push(ebx); // return address
+ Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
-
- // Return the generated code.
- return GetCode(flags);
-}
-
-
-MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
// ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
+ // -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- Label slow, check_heap_number;
- // Check that the object isn't a smi.
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &slow);
+ // Miss case: Jump to runtime.
+ __ bind(&miss_force_generic);
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+ __ jmp(miss_ic, RelocInfo::CODE_TARGET);
+}
- // Check that the map matches.
- __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
+
+void KeyedStoreStubCompiler::GenerateStoreExternalArray(
+ MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss_force_generic, slow, check_heap_number;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ test(ecx, Immediate(kSmiTagMask));
- __ j(not_zero, &slow);
+ __ j(not_zero, &miss_force_generic);
// Check that the index is in range.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
@@ -3559,7 +3617,7 @@
// edi: elements array
// ebx: untagged index
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
- Immediate(factory()->heap_number_map()));
+ Immediate(masm->isolate()->factory()->heap_number_map()));
__ j(not_equal, &slow);
// The WebGL specification leaves the behavior of storing NaN and
@@ -3654,6 +3712,9 @@
// Slow case: call runtime.
__ bind(&slow);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
+
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -3661,19 +3722,109 @@
// -- esp[0] : return address
// -----------------------------------
- __ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
- __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
- __ push(Immediate(Smi::FromInt(
- Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)));
- __ push(ebx); // return address
+ Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
- return GetCode(flags);
+ __ bind(&miss_force_generic);
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ jmp(miss_ic, RelocInfo::CODE_TARGET);
+}
+
+
+
+
+void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss_force_generic;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(not_zero, &miss_force_generic);
+
+ // Get the elements array.
+ __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ AssertFastElements(ecx);
+
+ // Check that the key is within bounds.
+ __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
+ __ j(above_equal, &miss_force_generic);
+
+ // Load the result and make sure it's not the hole.
+ __ mov(ebx, Operand(ecx, eax, times_2,
+ FixedArray::kHeaderSize - kHeapObjectTag));
+ __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
+ __ j(equal, &miss_force_generic);
+ __ mov(eax, ebx);
+ __ ret(0);
+
+ __ bind(&miss_force_generic);
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+ __ jmp(miss_ic, RelocInfo::CODE_TARGET);
+}
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
+ bool is_js_array) {
+ // ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss_force_generic;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ test(ecx, Immediate(kSmiTagMask));
+ __ j(not_zero, &miss_force_generic);
+
+ // Get the elements array and make sure it is a fast element array, not 'cow'.
+ __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+ __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
+ Immediate(masm->isolate()->factory()->fixed_array_map()));
+ __ j(not_equal, &miss_force_generic);
+
+ if (is_js_array) {
+ // Check that the key is within bounds.
+ __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
+ __ j(above_equal, &miss_force_generic);
+ } else {
+ // Check that the key is within bounds.
+ __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
+ __ j(above_equal, &miss_force_generic);
+ }
+
+ // Do the store and update the write barrier. Make sure to preserve
+ // the value in register eax.
+ __ mov(edx, Operand(eax));
+ __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
+ __ RecordWrite(edi, 0, edx, ecx);
+
+ // Done.
+ __ ret(0);
+
+ // Handle store cache miss, replacing the ic with the generic stub.
+ __ bind(&miss_force_generic);
+ Handle<Code> ic_force_generic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
}
diff --git a/src/ic.cc b/src/ic.cc
index 3f5326b..6d5c4df 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-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:
@@ -67,7 +67,33 @@
State new_state = StateFrom(new_target,
HEAP->undefined_value(),
HEAP->undefined_value());
- PrintF("[%s (%c->%c)%s", type,
+ PrintF("[%s in ", type);
+ StackFrameIterator it;
+ while (it.frame()->fp() != this->fp()) it.Advance();
+ StackFrame* raw_frame = it.frame();
+ if (raw_frame->is_internal()) {
+ Isolate* isolate = new_target->GetIsolate();
+ Code* apply_builtin = isolate->builtins()->builtin(
+ Builtins::kFunctionApply);
+ if (raw_frame->unchecked_code() == apply_builtin) {
+ PrintF("apply from ");
+ it.Advance();
+ raw_frame = it.frame();
+ }
+ }
+ if (raw_frame->is_java_script()) {
+ JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
+ Code* js_code = frame->unchecked_code();
+ // Find the function on the stack and both the active code for the
+ // function and the original code.
+ JSFunction* function = JSFunction::cast(frame->function());
+ function->PrintName();
+ int code_offset = address() - js_code->instruction_start();
+ PrintF("+%d", code_offset);
+ } else {
+ PrintF("<unknown>");
+ }
+ PrintF(" (%c->%c)%s",
TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state),
extra_info);
@@ -274,11 +300,9 @@
switch (target->kind()) {
case Code::LOAD_IC: return LoadIC::Clear(address, target);
case Code::KEYED_LOAD_IC:
- case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
return KeyedLoadIC::Clear(address, target);
case Code::STORE_IC: return StoreIC::Clear(address, target);
case Code::KEYED_STORE_IC:
- case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
return KeyedStoreIC::Clear(address, target);
case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
@@ -1032,9 +1056,49 @@
}
+String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) {
+ if (ic_state == MONOMORPHIC) {
+ return isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
+ } else {
+ ASSERT(ic_state == MEGAMORPHIC);
+ return isolate()->heap()->KeyedLoadSpecializedPolymorphic_symbol();
+ }
+}
+
+
+MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck(
+ bool is_js_array) {
+ return KeyedLoadFastElementStub().TryGetCode();
+}
+
+
+MaybeObject* KeyedLoadIC::GetExternalArrayStubWithoutMapCheck(
+ ExternalArrayType array_type) {
+ return KeyedLoadExternalArrayStub(array_type).TryGetCode();
+}
+
+
+MaybeObject* KeyedLoadIC::ConstructMegamorphicStub(
+ MapList* receiver_maps,
+ CodeList* targets,
+ StrictModeFlag strict_mode) {
+ Object* object;
+ KeyedLoadStubCompiler compiler;
+ MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps,
+ targets);
+ if (!maybe_code->ToObject(&object)) return maybe_code;
+ isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
+ PROFILE(isolate(), CodeCreateEvent(
+ Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG,
+ Code::cast(object), 0));
+ return object;
+}
+
+
MaybeObject* KeyedLoadIC::Load(State state,
Handle<Object> object,
- Handle<Object> key) {
+ Handle<Object> key,
+ bool force_generic_stub) {
// Check for values that can be converted into a symbol.
// TODO(1295): Remove this code.
HandleScope scope(isolate());
@@ -1160,34 +1224,31 @@
if (use_ic) {
Code* stub = generic_stub();
- if (state == UNINITIALIZED) {
+ if (!force_generic_stub) {
if (object->IsString() && key->IsNumber()) {
- stub = string_stub();
+ if (state == UNINITIALIZED) {
+ stub = string_stub();
+ }
} else if (object->IsJSObject()) {
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (receiver->HasExternalArrayElements()) {
- MaybeObject* probe =
- isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
- *receiver, false, kNonStrictMode);
- stub = probe->IsFailure() ?
- NULL : Code::cast(probe->ToObjectUnchecked());
- } else if (receiver->HasIndexedInterceptor()) {
+ JSObject* receiver = JSObject::cast(*object);
+ if (receiver->HasIndexedInterceptor()) {
stub = indexed_interceptor_stub();
- } else if (key->IsSmi() &&
- receiver->map()->has_fast_elements()) {
- MaybeObject* probe =
- isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver);
- stub = probe->IsFailure() ?
- NULL : Code::cast(probe->ToObjectUnchecked());
+ } else if (key->IsSmi()) {
+ MaybeObject* maybe_stub = ComputeStub(receiver,
+ false,
+ kNonStrictMode,
+ stub);
+ stub = maybe_stub->IsFailure() ?
+ NULL : Code::cast(maybe_stub->ToObjectUnchecked());
}
}
}
if (stub != NULL) set_target(stub);
+ }
#ifdef DEBUG
- TraceIC("KeyedLoadIC", key, state, target());
+ TraceIC("KeyedLoadIC", key, state, target());
#endif // DEBUG
- }
// Get the property.
return Runtime::GetObjectProperty(isolate(), object, key);
@@ -1484,11 +1545,256 @@
}
+static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
+ Map* new_receiver_map) {
+ for (int current = 0; current < receiver_maps->length(); ++current) {
+ if (receiver_maps->at(current) == new_receiver_map) {
+ return false;
+ }
+ }
+ receiver_maps->Add(new_receiver_map);
+ return true;
+}
+
+
+void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
+ ASSERT(stub->is_inline_cache_stub());
+ if (stub == string_stub()) {
+ return result->Add(isolate()->heap()->string_map());
+ } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
+ if (stub->ic_state() == MONOMORPHIC) {
+ result->Add(Map::cast(stub->FindFirstMap()));
+ } else {
+ ASSERT(stub->ic_state() == MEGAMORPHIC);
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(stub, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Object* object = info->target_object();
+ ASSERT(object->IsMap());
+ result->Add(Map::cast(object));
+ }
+ }
+ }
+}
+
+
+MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
+ bool is_store,
+ StrictModeFlag strict_mode,
+ Code* generic_stub) {
+ State ic_state = target()->ic_state();
+ Code* monomorphic_stub;
+ // Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up
+ // being used. This is necessary because the megamorphic stub needs to have
+ // access to more information than what is stored in the receiver map in some
+ // cases (external arrays need the array type from the MONOMORPHIC stub).
+ MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
+ is_store,
+ strict_mode,
+ generic_stub);
+ if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
+
+ if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
+ return monomorphic_stub;
+ }
+ ASSERT(target() != generic_stub);
+
+ // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
+ // via megamorphic stubs, since they don't have a map in their relocation info
+ // and so the stubs can't be harvested for the object needed for a map check.
+ if (target()->type() != NORMAL) {
+ return generic_stub;
+ }
+
+ // Determine the list of receiver maps that this call site has seen,
+ // adding the map that was just encountered.
+ MapList target_receiver_maps;
+ GetReceiverMapsForStub(target(), &target_receiver_maps);
+ if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) {
+ // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub
+ // won't help, use the generic stub.
+ return generic_stub;
+ }
+
+ // TODO(1385): Currently MEGAMORPHIC stubs are cached in the receiver map stub
+ // cache, but that can put receiver types together from unrelated call sites
+ // into the same stub--they always handle the union of all receiver maps seen
+ // at all call sites involving the receiver map. This is only an
+ // approximation: ideally, there would be a global cache that mapped sets of
+ // receiver maps to MEGAMORPHIC stubs. The complexity of the MEGAMORPHIC stub
+ // computation also leads to direct manipulation of the stub cache from the IC
+ // code, which the global cache solution would avoid.
+ Code::Kind kind = this->kind();
+ Code::Flags flags = Code::ComputeFlags(kind,
+ NOT_IN_LOOP,
+ MEGAMORPHIC,
+ strict_mode);
+ String* megamorphic_name = GetStubNameForCache(MEGAMORPHIC);
+ Object* maybe_cached_stub = receiver->map()->FindInCodeCache(megamorphic_name,
+ flags);
+
+ // Create a set of all receiver maps that have been seen at the IC call site
+ // and those seen by the MEGAMORPHIC cached stub, if that's the stub that's
+ // been selected.
+ MapList receiver_maps;
+ if (!maybe_cached_stub->IsUndefined()) {
+ GetReceiverMapsForStub(Code::cast(maybe_cached_stub), &receiver_maps);
+ }
+ bool added_map = false;
+ for (int i = 0; i < target_receiver_maps.length(); ++i) {
+ if (AddOneReceiverMapIfMissing(&receiver_maps,
+ target_receiver_maps.at(i))) {
+ added_map = true;
+ }
+ }
+ ASSERT(receiver_maps.length() > 0);
+
+ // If the maximum number of receiver maps has been exceeded, use the Generic
+ // version of the IC.
+ if (receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) {
+ return generic_stub;
+ }
+
+ // If no maps have been seen at the call site that aren't in the cached
+ // stub, then use it.
+ if (!added_map) {
+ ASSERT(!maybe_cached_stub->IsUndefined());
+ ASSERT(maybe_cached_stub->IsCode());
+ return Code::cast(maybe_cached_stub);
+ }
+
+ // Lookup all of the receiver maps in the cache, they should all already
+ // have MONOMORPHIC stubs.
+ CodeList handler_ics(KeyedIC::kMaxKeyedPolymorphism);
+ for (int current = 0; current < receiver_maps.length(); ++current) {
+ Map* receiver_map(receiver_maps.at(current));
+ MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
+ receiver_map,
+ strict_mode,
+ generic_stub);
+ Code* cached_stub;
+ if (!maybe_cached_stub->To(&cached_stub)) {
+ return maybe_cached_stub;
+ }
+ handler_ics.Add(cached_stub);
+ }
+
+ Code* stub;
+ // Build the MEGAMORPHIC stub.
+ maybe_stub = ConstructMegamorphicStub(&receiver_maps,
+ &handler_ics,
+ strict_mode);
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+
+ MaybeObject* maybe_update = receiver->UpdateMapCodeCache(
+ megamorphic_name,
+ stub);
+ if (maybe_update->IsFailure()) return maybe_update;
+ return stub;
+}
+
+
+MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
+ Map* receiver_map,
+ StrictModeFlag strict_mode,
+ Code* generic_stub) {
+ if ((receiver_map->instance_type() & kNotStringTag) == 0) {
+ ASSERT(string_stub() != NULL);
+ return string_stub();
+ } else if (receiver_map->has_external_array_elements()) {
+ // Determine the array type from the default MONOMORPHIC already generated
+ // stub. There is no other way to determine the type of the external array
+ // directly from the receiver type.
+ Code::Kind kind = this->kind();
+ Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
+ NORMAL,
+ strict_mode);
+ String* monomorphic_name = GetStubNameForCache(MONOMORPHIC);
+ Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name,
+ flags);
+ if (maybe_default_stub->IsUndefined()) {
+ return generic_stub;
+ }
+ Code* default_stub = Code::cast(maybe_default_stub);
+ return GetExternalArrayStubWithoutMapCheck(
+ default_stub->external_array_type());
+ } else if (receiver_map->has_fast_elements()) {
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ return GetFastElementStubWithoutMapCheck(is_js_array);
+ } else {
+ return generic_stub;
+ }
+}
+
+
+MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
+ bool is_store,
+ StrictModeFlag strict_mode,
+ Code* generic_stub) {
+ Code* result = NULL;
+ if (receiver->HasExternalArrayElements()) {
+ MaybeObject* maybe_stub =
+ isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
+ receiver, is_store, strict_mode);
+ if (!maybe_stub->To(&result)) return maybe_stub;
+ } else if (receiver->map()->has_fast_elements()) {
+ MaybeObject* maybe_stub =
+ isolate()->stub_cache()->ComputeKeyedLoadOrStoreFastElement(
+ receiver, is_store, strict_mode);
+ if (!maybe_stub->To(&result)) return maybe_stub;
+ } else {
+ result = generic_stub;
+ }
+ return result;
+}
+
+
+String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) {
+ if (ic_state == MONOMORPHIC) {
+ return isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol();
+ } else {
+ ASSERT(ic_state == MEGAMORPHIC);
+ return isolate()->heap()->KeyedStoreSpecializedPolymorphic_symbol();
+ }
+}
+
+
+MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck(
+ bool is_js_array) {
+ return KeyedStoreFastElementStub(is_js_array).TryGetCode();
+}
+
+
+MaybeObject* KeyedStoreIC::GetExternalArrayStubWithoutMapCheck(
+ ExternalArrayType array_type) {
+ return KeyedStoreExternalArrayStub(array_type).TryGetCode();
+}
+
+
+MaybeObject* KeyedStoreIC::ConstructMegamorphicStub(
+ MapList* receiver_maps,
+ CodeList* targets,
+ StrictModeFlag strict_mode) {
+ Object* object;
+ KeyedStoreStubCompiler compiler(strict_mode);
+ MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps,
+ targets);
+ if (!maybe_code->ToObject(&object)) return maybe_code;
+ isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
+ PROFILE(isolate(), CodeCreateEvent(
+ Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG,
+ Code::cast(object), 0));
+ return object;
+}
+
+
MaybeObject* KeyedStoreIC::Store(State state,
StrictModeFlag strict_mode,
Handle<Object> object,
Handle<Object> key,
- Handle<Object> value) {
+ Handle<Object> value,
+ bool force_generic) {
if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key);
@@ -1530,29 +1836,27 @@
ASSERT(!(use_ic && object->IsJSGlobalProxy()));
if (use_ic) {
- Code* stub =
- (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub();
- if (state == UNINITIALIZED) {
- if (object->IsJSObject()) {
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (receiver->HasExternalArrayElements()) {
- MaybeObject* probe =
- isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
- *receiver, true, strict_mode);
- stub = probe->IsFailure() ?
- NULL : Code::cast(probe->ToObjectUnchecked());
- } else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
- MaybeObject* probe =
- isolate()->stub_cache()->ComputeKeyedStoreSpecialized(
- *receiver, strict_mode);
- stub = probe->IsFailure() ?
- NULL : Code::cast(probe->ToObjectUnchecked());
- }
+ Code* stub = (strict_mode == kStrictMode)
+ ? generic_stub_strict()
+ : generic_stub();
+ if (!force_generic) {
+ if (object->IsJSObject() && key->IsSmi()) {
+ JSObject* receiver = JSObject::cast(*object);
+ MaybeObject* maybe_stub = ComputeStub(receiver,
+ true,
+ strict_mode,
+ stub);
+ stub = maybe_stub->IsFailure() ?
+ NULL : Code::cast(maybe_stub->ToObjectUnchecked());
}
}
if (stub != NULL) set_target(stub);
}
+#ifdef DEBUG
+ TraceIC("KeyedStoreIC", key, state, target());
+#endif
+
// Set the property.
return Runtime::SetObjectProperty(
isolate(), object , key, value, NONE, strict_mode);
@@ -1721,7 +2025,16 @@
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
- return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
+ return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
+ NoHandleAllocation na;
+ ASSERT(args.length() == 2);
+ KeyedLoadIC ic(isolate);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
+ return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true);
}
@@ -1805,7 +2118,42 @@
static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
args.at<Object>(0),
args.at<Object>(1),
- args.at<Object>(2));
+ args.at<Object>(2),
+ false);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
+ NoHandleAllocation na;
+ ASSERT(args.length() == 3);
+ KeyedStoreIC ic(isolate);
+ Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
+ Handle<Object> object = args.at<Object>(0);
+ Handle<Object> key = args.at<Object>(1);
+ Handle<Object> value = args.at<Object>(2);
+ StrictModeFlag strict_mode =
+ static_cast<StrictModeFlag>(extra_ic_state & kStrictMode);
+ return Runtime::SetObjectProperty(isolate,
+ object,
+ key,
+ value,
+ NONE,
+ strict_mode);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
+ NoHandleAllocation na;
+ ASSERT(args.length() == 3);
+ KeyedStoreIC ic(isolate);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
+ Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
+ return ic.Store(state,
+ static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
+ args.at<Object>(0),
+ args.at<Object>(1),
+ args.at<Object>(2),
+ true);
}
@@ -1852,9 +2200,25 @@
}
-TRUnaryOpIC::TypeInfo TRUnaryOpIC::JoinTypes(TRUnaryOpIC::TypeInfo x,
- TRUnaryOpIC::TypeInfo y) {
- return x >= y ? x : y;
+TRUnaryOpIC::TypeInfo TRUnaryOpIC::ComputeNewType(
+ TRUnaryOpIC::TypeInfo type,
+ TRUnaryOpIC::TypeInfo previous) {
+ switch (previous) {
+ case TRUnaryOpIC::UNINITIALIZED:
+ return type;
+ case TRUnaryOpIC::SMI:
+ return (type == TRUnaryOpIC::GENERIC)
+ ? TRUnaryOpIC::GENERIC
+ : TRUnaryOpIC::HEAP_NUMBER;
+ case TRUnaryOpIC::HEAP_NUMBER:
+ return TRUnaryOpIC::GENERIC;
+ case TRUnaryOpIC::GENERIC:
+ // We should never do patching if we are in GENERIC state.
+ UNREACHABLE();
+ return TRUnaryOpIC::GENERIC;
+ }
+ UNREACHABLE();
+ return TRUnaryOpIC::GENERIC;
}
@@ -1966,7 +2330,7 @@
static_cast<TRUnaryOpIC::TypeInfo>(Smi::cast(args[3])->value());
TRUnaryOpIC::TypeInfo type = TRUnaryOpIC::GetTypeInfo(operand);
- type = TRUnaryOpIC::JoinTypes(type, previous_type);
+ type = TRUnaryOpIC::ComputeNewType(type, previous_type);
Handle<Code> code = GetTypeRecordingUnaryOpStub(key, type);
if (!code.is_null()) {
@@ -2031,7 +2395,10 @@
type = TRBinaryOpIC::GENERIC;
}
if (type == TRBinaryOpIC::SMI && previous_type == TRBinaryOpIC::SMI) {
- if (op == Token::DIV || op == Token::MUL || kSmiValueSize == 32) {
+ if (op == Token::DIV ||
+ op == Token::MUL ||
+ op == Token::SHR ||
+ kSmiValueSize == 32) {
// Arithmetic on two Smi inputs has yielded a heap number.
// That is the only way to get here from the Smi stub.
// With 32-bit Smis, all overflows give heap numbers, but with
diff --git a/src/ic.h b/src/ic.h
index 0591674..461f8b7 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -1,4 +1,4 @@
-// Copyright 2006-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:
@@ -39,12 +39,15 @@
#define IC_UTIL_LIST(ICU) \
ICU(LoadIC_Miss) \
ICU(KeyedLoadIC_Miss) \
+ ICU(KeyedLoadIC_MissForceGeneric) \
ICU(CallIC_Miss) \
ICU(KeyedCallIC_Miss) \
ICU(StoreIC_Miss) \
ICU(StoreIC_ArrayLength) \
ICU(SharedStoreIC_ExtendStorage) \
ICU(KeyedStoreIC_Miss) \
+ ICU(KeyedStoreIC_MissForceGeneric) \
+ ICU(KeyedStoreIC_Slow) \
/* Utilities for IC stubs. */ \
ICU(LoadCallbackProperty) \
ICU(StoreCallbackProperty) \
@@ -142,11 +145,11 @@
void set_target(Code* code) { SetTargetAtAddress(address(), code); }
#ifdef DEBUG
- static void TraceIC(const char* type,
- Handle<Object> name,
- State old_state,
- Code* new_target,
- const char* extra_info = "");
+ void TraceIC(const char* type,
+ Handle<Object> name,
+ State old_state,
+ Code* new_target,
+ const char* extra_info = "");
#endif
Failure* TypeError(const char* type,
@@ -325,23 +328,72 @@
};
-class KeyedLoadIC: public IC {
+class KeyedIC: public IC {
public:
- explicit KeyedLoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
- ASSERT(target()->is_keyed_load_stub() ||
- target()->is_external_array_load_stub());
+ explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
+ virtual ~KeyedIC() {}
+
+ static const int kMaxKeyedPolymorphism = 4;
+
+ virtual MaybeObject* GetFastElementStubWithoutMapCheck(
+ bool is_js_array) = 0;
+
+ virtual MaybeObject* GetExternalArrayStubWithoutMapCheck(
+ ExternalArrayType array_type) = 0;
+
+ protected:
+ virtual Code* string_stub() {
+ return NULL;
+ }
+
+ virtual Code::Kind kind() const = 0;
+
+ virtual String* GetStubNameForCache(IC::State ic_state) = 0;
+
+ MaybeObject* ComputeStub(JSObject* receiver,
+ bool is_store,
+ StrictModeFlag strict_mode,
+ Code* default_stub);
+
+ virtual MaybeObject* ConstructMegamorphicStub(
+ MapList* receiver_maps,
+ CodeList* targets,
+ StrictModeFlag strict_mode) = 0;
+
+ private:
+ void GetReceiverMapsForStub(Code* stub, MapList* result);
+
+ MaybeObject* ComputeMonomorphicStubWithoutMapCheck(
+ Map* receiver_map,
+ StrictModeFlag strict_mode,
+ Code* generic_stub);
+
+ MaybeObject* ComputeMonomorphicStub(JSObject* receiver,
+ bool is_store,
+ StrictModeFlag strict_mode,
+ Code* default_stub);
+};
+
+
+class KeyedLoadIC: public KeyedIC {
+ public:
+ explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
+ ASSERT(target()->is_keyed_load_stub());
}
MUST_USE_RESULT MaybeObject* Load(State state,
Handle<Object> object,
- Handle<Object> key);
+ Handle<Object> key,
+ bool force_generic_stub);
// Code generator routines.
- static void GenerateMiss(MacroAssembler* masm);
+ static void GenerateMiss(MacroAssembler* masm, bool force_generic);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
- static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
+ static void GenerateInitialize(MacroAssembler* masm) {
+ GenerateMiss(masm, false);
+ }
static void GeneratePreMonomorphic(MacroAssembler* masm) {
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
static void GenerateGeneric(MacroAssembler* masm);
static void GenerateString(MacroAssembler* masm);
@@ -355,6 +407,27 @@
static const int kSlowCaseBitFieldMask =
(1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
+ virtual MaybeObject* GetFastElementStubWithoutMapCheck(
+ bool is_js_array);
+
+ virtual MaybeObject* GetExternalArrayStubWithoutMapCheck(
+ ExternalArrayType array_type);
+
+ protected:
+ virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
+
+ virtual String* GetStubNameForCache(IC::State ic_state);
+
+ virtual MaybeObject* ConstructMegamorphicStub(
+ MapList* receiver_maps,
+ CodeList* targets,
+ StrictModeFlag strict_mode);
+
+ virtual Code* string_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_String);
+ }
+
private:
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,
@@ -379,11 +452,6 @@
return isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_PreMonomorphic);
}
- Code* string_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_String);
- }
-
Code* indexed_interceptor_stub() {
return isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_IndexedInterceptor);
@@ -466,24 +534,46 @@
};
-class KeyedStoreIC: public IC {
+class KeyedStoreIC: public KeyedIC {
public:
- explicit KeyedStoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
+ explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
+ ASSERT(target()->is_keyed_store_stub());
+ }
MUST_USE_RESULT MaybeObject* Store(State state,
- StrictModeFlag strict_mode,
+ StrictModeFlag strict_mode,
Handle<Object> object,
Handle<Object> name,
- Handle<Object> value);
+ Handle<Object> value,
+ bool force_generic);
// Code generators for stub routines. Only called once at startup.
- static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
- static void GenerateMiss(MacroAssembler* masm);
+ static void GenerateInitialize(MacroAssembler* masm) {
+ GenerateMiss(masm, false);
+ }
+ static void GenerateMiss(MacroAssembler* masm, bool force_generic);
+ static void GenerateSlow(MacroAssembler* masm);
static void GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictModeFlag strict_mode);
static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
- private:
+ virtual MaybeObject* GetFastElementStubWithoutMapCheck(
+ bool is_js_array);
+
+ virtual MaybeObject* GetExternalArrayStubWithoutMapCheck(
+ ExternalArrayType array_type);
+
+ protected:
+ virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
+
+ virtual String* GetStubNameForCache(IC::State ic_state);
+
+ virtual MaybeObject* ConstructMegamorphicStub(
+ MapList* receiver_maps,
+ CodeList* targets,
+ StrictModeFlag strict_mode);
+
+ private:
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,
State state,
@@ -553,7 +643,7 @@
static TypeInfo GetTypeInfo(Handle<Object> operand);
- static TypeInfo JoinTypes(TypeInfo x, TypeInfo y);
+ static TypeInfo ComputeNewType(TypeInfo type, TypeInfo previous);
};
diff --git a/src/isolate.cc b/src/isolate.cc
index 9fac06a..a7bf7d9 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -896,13 +896,15 @@
Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) {
bool can_be_caught_externally = false;
- ShouldReportException(&can_be_caught_externally,
- is_catchable_by_javascript(exception));
+ bool catchable_by_javascript = is_catchable_by_javascript(exception);
+ ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
+
thread_local_top()->catcher_ = can_be_caught_externally ?
try_catch_handler() : NULL;
// Set the exception being re-thrown.
set_pending_exception(exception);
+ if (exception->IsFailure()) return exception->ToFailureUnchecked();
return Failure::Exception();
}
@@ -1395,7 +1397,8 @@
string_tracker_(NULL),
regexp_stack_(NULL),
frame_element_constant_list_(0),
- result_constant_list_(0) {
+ result_constant_list_(0),
+ embedder_data_(NULL) {
TRACE_ISOLATE(constructor);
memset(isolate_addresses_, 0,
diff --git a/src/isolate.h b/src/isolate.h
index 088c247..fbe0b43 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -994,6 +994,9 @@
void ResetEagerOptimizingData();
+ void SetData(void* data) { embedder_data_ = data; }
+ void* GetData() { return embedder_data_; }
+
private:
Isolate();
@@ -1156,6 +1159,7 @@
unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_;
ZoneObjectList frame_element_constant_list_;
ZoneObjectList result_constant_list_;
+ void* embedder_data_;
#if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__)
diff --git a/src/list.h b/src/list.h
index ef79557..ca2b7bc 100644
--- a/src/list.h
+++ b/src/list.h
@@ -164,6 +164,11 @@
DISALLOW_COPY_AND_ASSIGN(List);
};
+class Map;
+class Code;
+typedef List<Map*> MapList;
+typedef List<Code*> CodeList;
+
} } // namespace v8::internal
#endif // V8_LIST_H_
diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc
index 5795a6b..29a9b01 100644
--- a/src/liveobjectlist.cc
+++ b/src/liveobjectlist.cc
@@ -118,7 +118,7 @@
v(Code, "meta: Code") \
v(Map, "meta: Map") \
v(Oddball, "Oddball") \
- v(Proxy, "meta: Proxy") \
+ v(Foreign, "meta: Foreign") \
v(SharedFunctionInfo, "meta: SharedFunctionInfo") \
v(Struct, "meta: Struct") \
\
diff --git a/src/log.cc b/src/log.cc
index 8cb7ab5..512a231 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -1,4 +1,4 @@
-// Copyright 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:
@@ -1005,6 +1005,7 @@
name_buffer_->Reset();
name_buffer_->AppendBytes(kLogEventsNames[tag]);
name_buffer_->AppendByte(':');
+ name_buffer_->AppendBytes(ComputeMarker(code));
name_buffer_->AppendString(name);
}
if (FLAG_ll_prof) {
@@ -1047,6 +1048,7 @@
name_buffer_->Reset();
name_buffer_->AppendBytes(kLogEventsNames[tag]);
name_buffer_->AppendByte(':');
+ name_buffer_->AppendBytes(ComputeMarker(code));
name_buffer_->AppendString(shared->DebugName());
name_buffer_->AppendByte(' ');
name_buffer_->AppendString(source);
@@ -1620,10 +1622,6 @@
description = "A keyed load IC from the snapshot";
tag = Logger::KEYED_LOAD_IC_TAG;
break;
- case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
- description = "A keyed external array load IC from the snapshot";
- tag = Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG;
- break;
case Code::LOAD_IC:
description = "A load IC from the snapshot";
tag = Logger::LOAD_IC_TAG;
@@ -1636,10 +1634,6 @@
description = "A keyed store IC from the snapshot";
tag = Logger::KEYED_STORE_IC_TAG;
break;
- case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
- description = "A keyed external array store IC from the snapshot";
- tag = Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG;
- break;
case Code::CALL_IC:
description = "A call IC from the snapshot";
tag = Logger::CALL_IC_TAG;
diff --git a/src/log.h b/src/log.h
index 3434b73..a96e171 100644
--- a/src/log.h
+++ b/src/log.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 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:
@@ -90,49 +90,51 @@
#define LOG(isolate, Call) ((void) 0)
#endif
-#define LOG_EVENTS_AND_TAGS_LIST(V) \
- V(CODE_CREATION_EVENT, "code-creation") \
- V(CODE_MOVE_EVENT, "code-move") \
- V(CODE_DELETE_EVENT, "code-delete") \
- V(CODE_MOVING_GC, "code-moving-gc") \
- V(SHARED_FUNC_MOVE_EVENT, "sfi-move") \
- V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \
- V(SNAPSHOT_CODE_NAME_EVENT, "snapshot-code-name") \
- V(TICK_EVENT, "tick") \
- V(REPEAT_META_EVENT, "repeat") \
- V(BUILTIN_TAG, "Builtin") \
- V(CALL_DEBUG_BREAK_TAG, "CallDebugBreak") \
- V(CALL_DEBUG_PREPARE_STEP_IN_TAG, "CallDebugPrepareStepIn") \
- V(CALL_IC_TAG, "CallIC") \
- V(CALL_INITIALIZE_TAG, "CallInitialize") \
- V(CALL_MEGAMORPHIC_TAG, "CallMegamorphic") \
- V(CALL_MISS_TAG, "CallMiss") \
- V(CALL_NORMAL_TAG, "CallNormal") \
- V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic") \
- V(KEYED_CALL_DEBUG_BREAK_TAG, "KeyedCallDebugBreak") \
- V(KEYED_CALL_DEBUG_PREPARE_STEP_IN_TAG, \
- "KeyedCallDebugPrepareStepIn") \
- V(KEYED_CALL_IC_TAG, "KeyedCallIC") \
- V(KEYED_CALL_INITIALIZE_TAG, "KeyedCallInitialize") \
- V(KEYED_CALL_MEGAMORPHIC_TAG, "KeyedCallMegamorphic") \
- V(KEYED_CALL_MISS_TAG, "KeyedCallMiss") \
- V(KEYED_CALL_NORMAL_TAG, "KeyedCallNormal") \
- V(KEYED_CALL_PRE_MONOMORPHIC_TAG, "KeyedCallPreMonomorphic") \
- V(CALLBACK_TAG, "Callback") \
- V(EVAL_TAG, "Eval") \
- V(FUNCTION_TAG, "Function") \
- V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \
- V(KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG, "KeyedExternalArrayLoadIC") \
- V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \
- V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC")\
- V(LAZY_COMPILE_TAG, "LazyCompile") \
- V(LOAD_IC_TAG, "LoadIC") \
- V(REG_EXP_TAG, "RegExp") \
- V(SCRIPT_TAG, "Script") \
- V(STORE_IC_TAG, "StoreIC") \
- V(STUB_TAG, "Stub") \
- V(NATIVE_FUNCTION_TAG, "Function") \
- V(NATIVE_LAZY_COMPILE_TAG, "LazyCompile") \
+#define LOG_EVENTS_AND_TAGS_LIST(V) \
+ V(CODE_CREATION_EVENT, "code-creation") \
+ V(CODE_MOVE_EVENT, "code-move") \
+ V(CODE_DELETE_EVENT, "code-delete") \
+ V(CODE_MOVING_GC, "code-moving-gc") \
+ V(SHARED_FUNC_MOVE_EVENT, "sfi-move") \
+ V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \
+ V(SNAPSHOT_CODE_NAME_EVENT, "snapshot-code-name") \
+ V(TICK_EVENT, "tick") \
+ V(REPEAT_META_EVENT, "repeat") \
+ V(BUILTIN_TAG, "Builtin") \
+ V(CALL_DEBUG_BREAK_TAG, "CallDebugBreak") \
+ V(CALL_DEBUG_PREPARE_STEP_IN_TAG, "CallDebugPrepareStepIn") \
+ V(CALL_IC_TAG, "CallIC") \
+ V(CALL_INITIALIZE_TAG, "CallInitialize") \
+ V(CALL_MEGAMORPHIC_TAG, "CallMegamorphic") \
+ V(CALL_MISS_TAG, "CallMiss") \
+ V(CALL_NORMAL_TAG, "CallNormal") \
+ V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic") \
+ V(KEYED_CALL_DEBUG_BREAK_TAG, "KeyedCallDebugBreak") \
+ V(KEYED_CALL_DEBUG_PREPARE_STEP_IN_TAG, \
+ "KeyedCallDebugPrepareStepIn") \
+ V(KEYED_CALL_IC_TAG, "KeyedCallIC") \
+ V(KEYED_CALL_INITIALIZE_TAG, "KeyedCallInitialize") \
+ V(KEYED_CALL_MEGAMORPHIC_TAG, "KeyedCallMegamorphic") \
+ V(KEYED_CALL_MISS_TAG, "KeyedCallMiss") \
+ V(KEYED_CALL_NORMAL_TAG, "KeyedCallNormal") \
+ V(KEYED_CALL_PRE_MONOMORPHIC_TAG, "KeyedCallPreMonomorphic") \
+ V(CALLBACK_TAG, "Callback") \
+ V(EVAL_TAG, "Eval") \
+ V(FUNCTION_TAG, "Function") \
+ V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \
+ V(KEYED_LOAD_MEGAMORPHIC_IC_TAG, "KeyedLoadMegamorphicIC") \
+ V(KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG, "KeyedExternalArrayLoadIC") \
+ V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \
+ V(KEYED_STORE_MEGAMORPHIC_IC_TAG, "KeyedStoreMegamorphicIC") \
+ V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC") \
+ V(LAZY_COMPILE_TAG, "LazyCompile") \
+ V(LOAD_IC_TAG, "LoadIC") \
+ V(REG_EXP_TAG, "RegExp") \
+ V(SCRIPT_TAG, "Script") \
+ V(STORE_IC_TAG, "StoreIC") \
+ V(STUB_TAG, "Stub") \
+ V(NATIVE_FUNCTION_TAG, "Function") \
+ V(NATIVE_LAZY_COMPILE_TAG, "LazyCompile") \
V(NATIVE_SCRIPT_TAG, "Script")
// Note that 'NATIVE_' cases for functions and scripts are mapped onto
// original tags when writing to the log.
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 4071073..b82c76a 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -457,7 +457,7 @@
static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address());
- if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
+ if (FLAG_cleanup_code_caches_at_gc && code->is_inline_cache_stub()) {
IC::Clear(rinfo->pc());
// Please note targets for cleared inline cached do not have to be
// marked since they are contained in HEAP->non_monomorphic_cache().
@@ -1056,7 +1056,7 @@
ASSERT(HEAP->Contains(object));
if (object->IsMap()) {
Map* map = Map::cast(object);
- if (FLAG_cleanup_caches_in_maps_at_gc) {
+ if (FLAG_cleanup_code_caches_at_gc) {
map->ClearCodeCache(heap());
}
SetMark(map);
diff --git a/src/messages.cc b/src/messages.cc
index 0fdbbbb..4cbf0af 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -125,9 +125,9 @@
HandleScope scope;
if (global_listeners.get(i)->IsUndefined()) continue;
v8::NeanderObject listener(JSObject::cast(global_listeners.get(i)));
- Handle<Proxy> callback_obj(Proxy::cast(listener.get(0)));
+ Handle<Foreign> callback_obj(Foreign::cast(listener.get(0)));
v8::MessageCallback callback =
- FUNCTION_CAST<v8::MessageCallback>(callback_obj->proxy());
+ FUNCTION_CAST<v8::MessageCallback>(callback_obj->address());
Handle<Object> callback_data(listener.get(1));
{
// Do not allow exceptions to propagate.
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 89981fd..dd4e7c1 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -6613,4 +6613,3 @@
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS
-
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 45df93a..5ab8e11 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -2255,6 +2255,7 @@
// repatch it to global receiver.
if (object->IsGlobalObject()) return heap->undefined_value();
if (cell != NULL) return heap->undefined_value();
+ if (!object->IsJSObject()) return heap()->undefined_value();
int depth = optimization.GetPrototypeDepthOfExpectedType(
JSObject::cast(object), holder);
if (depth == kInvalidProtoDepth) return heap->undefined_value();
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index ba78253..05ae00c 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -158,8 +158,8 @@
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyVerify();
break;
- case PROXY_TYPE:
- Proxy::cast(this)->ProxyVerify();
+ case FOREIGN_TYPE:
+ Foreign::cast(this)->ForeignVerify();
break;
case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify();
@@ -469,8 +469,8 @@
VerifyPointer(handler());
}
-void Proxy::ProxyVerify() {
- ASSERT(IsProxy());
+void Foreign::ForeignVerify() {
+ ASSERT(IsForeign());
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index c96bf56..841fcbc 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -590,9 +590,9 @@
}
-bool Object::IsProxy() {
+bool Object::IsForeign() {
return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE;
+ && HeapObject::cast(this)->map()->instance_type() == FOREIGN_TYPE;
}
@@ -1757,8 +1757,8 @@
AccessorDescriptor* DescriptorArray::GetCallbacks(int descriptor_number) {
ASSERT(GetType(descriptor_number) == CALLBACKS);
- Proxy* p = Proxy::cast(GetCallbacksObject(descriptor_number));
- return reinterpret_cast<AccessorDescriptor*>(p->proxy());
+ Foreign* p = Foreign::cast(GetCallbacksObject(descriptor_number));
+ return reinterpret_cast<AccessorDescriptor*>(p->address());
}
@@ -1905,7 +1905,7 @@
CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSProxy)
-CAST_ACCESSOR(Proxy)
+CAST_ACCESSOR(Foreign)
CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(ExternalArray)
CAST_ACCESSOR(ExternalByteArray)
@@ -2595,7 +2595,6 @@
PropertyType Code::type() {
- ASSERT(ic_state() == MONOMORPHIC);
return ExtractTypeFromFlags(flags());
}
@@ -2713,14 +2712,14 @@
ExternalArrayType Code::external_array_type() {
- ASSERT(is_external_array_load_stub() || is_external_array_store_stub());
+ ASSERT(is_keyed_load_stub() || is_keyed_store_stub());
byte type = READ_BYTE_FIELD(this, kExternalArrayTypeOffset);
return static_cast<ExternalArrayType>(type);
}
void Code::set_external_array_type(ExternalArrayType value) {
- ASSERT(is_external_array_load_stub() || is_external_array_store_stub());
+ ASSERT(is_keyed_load_stub() || is_keyed_store_stub());
WRITE_BYTE_FIELD(this, kExternalArrayTypeOffset, value);
}
@@ -2792,8 +2791,7 @@
(kind == CALL_IC && (ic_state == MONOMORPHIC ||
ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)) ||
(kind == STORE_IC) ||
- (kind == KEYED_STORE_IC) ||
- (kind == KEYED_EXTERNAL_ARRAY_STORE_IC));
+ (kind == KEYED_STORE_IC));
// Compute the bit mask.
int bits = kind << kFlagsKindShift;
if (in_loop) bits |= kFlagsICInLoopMask;
@@ -3046,7 +3044,7 @@
ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset)
ACCESSORS(Script, data, Object, kDataOffset)
ACCESSORS(Script, context_data, Object, kContextOffset)
-ACCESSORS(Script, wrapper, Proxy, kWrapperOffset)
+ACCESSORS(Script, wrapper, Foreign, kWrapperOffset)
ACCESSORS(Script, type, Smi, kTypeOffset)
ACCESSORS(Script, compilation_type, Smi, kCompilationTypeOffset)
ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
@@ -3531,13 +3529,13 @@
ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
-Address Proxy::proxy() {
- return AddressFrom<Address>(READ_INTPTR_FIELD(this, kProxyOffset));
+Address Foreign::address() {
+ return AddressFrom<Address>(READ_INTPTR_FIELD(this, kAddressOffset));
}
-void Proxy::set_proxy(Address value) {
- WRITE_INTPTR_FIELD(this, kProxyOffset, OffsetFrom(value));
+void Foreign::set_address(Address value) {
+ WRITE_INTPTR_FIELD(this, kAddressOffset, OffsetFrom(value));
}
@@ -4150,16 +4148,16 @@
}
-void Proxy::ProxyIterateBody(ObjectVisitor* v) {
+void Foreign::ForeignIterateBody(ObjectVisitor* v) {
v->VisitExternalReference(
- reinterpret_cast<Address *>(FIELD_ADDR(this, kProxyOffset)));
+ reinterpret_cast<Address *>(FIELD_ADDR(this, kAddressOffset)));
}
template<typename StaticVisitor>
-void Proxy::ProxyIterateBody() {
+void Foreign::ForeignIterateBody() {
StaticVisitor::VisitExternalReference(
- reinterpret_cast<Address *>(FIELD_ADDR(this, kProxyOffset)));
+ reinterpret_cast<Address *>(FIELD_ADDR(this, kAddressOffset)));
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 7a584ba..60028c0 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -151,8 +151,8 @@
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyPrint(out);
break;
- case PROXY_TYPE:
- Proxy::cast(this)->ProxyPrint(out);
+ case FOREIGN_TYPE:
+ Foreign::cast(this)->ForeignPrint(out);
break;
case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out);
@@ -417,7 +417,7 @@
case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT";
case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT";
case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
- case PROXY_TYPE: return "PROXY";
+ case FOREIGN_TYPE: return "FOREIGN";
case JS_MESSAGE_OBJECT_TYPE: return "JS_MESSAGE_OBJECT_TYPE";
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
STRUCT_LIST(MAKE_STRUCT_CASE)
@@ -635,8 +635,8 @@
}
-void Proxy::ProxyPrint(FILE* out) {
- PrintF(out, "proxy to %p", proxy());
+void Foreign::ForeignPrint(FILE* out) {
+ PrintF(out, "foreign address : %p", address());
}
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index eab864b..8a6620d 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -93,10 +93,10 @@
kVisitDataObjectGeneric,
JSProxy::kSize);
- case PROXY_TYPE:
+ case FOREIGN_TYPE:
return GetVisitorIdForSize(kVisitDataObject,
kVisitDataObjectGeneric,
- Proxy::kSize);
+ Foreign::kSize);
case FILLER_TYPE:
return kVisitDataObjectGeneric;
diff --git a/src/objects.cc b/src/objects.cc
index 8c7695d..d81e198 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -174,11 +174,12 @@
Object* holder) {
Isolate* isolate = name->GetIsolate();
// To accommodate both the old and the new api we switch on the
- // data structure used to store the callbacks. Eventually proxy
+ // data structure used to store the callbacks. Eventually foreign
// callbacks should be phased out.
- if (structure->IsProxy()) {
+ if (structure->IsForeign()) {
AccessorDescriptor* callback =
- reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
+ reinterpret_cast<AccessorDescriptor*>(
+ Foreign::cast(structure)->address());
MaybeObject* value = (callback->getter)(receiver, callback->data);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return value;
@@ -239,9 +240,7 @@
Handle<Object> trap(v8::internal::GetProperty(handler, "get", &lookup));
if (!lookup.IsFound()) {
// Get the derived `get' property.
- Object* derived = isolate->global_context()->builtins()->javascript_builtin(
- Builtins::DERIVED_GET_TRAP);
- trap = Handle<JSFunction>(JSFunction::cast(derived));
+ trap = isolate->derived_get_trap();
}
// Call trap function.
@@ -1128,8 +1127,8 @@
HeapNumber::cast(this)->HeapNumberPrint(accumulator);
accumulator->Put('>');
break;
- case PROXY_TYPE:
- accumulator->Add("<Proxy>");
+ case FOREIGN_TYPE:
+ accumulator->Add("<Foreign>");
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
accumulator->Add("Cell for ");
@@ -1200,8 +1199,8 @@
case JS_PROXY_TYPE:
JSProxy::BodyDescriptor::IterateBody(this, v);
break;
- case PROXY_TYPE:
- reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
+ case FOREIGN_TYPE:
+ reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
break;
case MAP_TYPE:
Map::BodyDescriptor::IterateBody(this, v);
@@ -1782,11 +1781,12 @@
Handle<Object> value_handle(value, isolate);
// To accommodate both the old and the new api we switch on the
- // data structure used to store the callbacks. Eventually proxy
+ // data structure used to store the callbacks. Eventually foreign
// callbacks should be phased out.
- if (structure->IsProxy()) {
+ if (structure->IsForeign()) {
AccessorDescriptor* callback =
- reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
+ reinterpret_cast<AccessorDescriptor*>(
+ Foreign::cast(structure)->address());
MaybeObject* obj = (callback->setter)(this, value, callback->data);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (obj->IsFailure()) return obj;
@@ -3811,8 +3811,6 @@
MaybeObject* CodeCache::Update(String* name, Code* code) {
- ASSERT(code->ic_state() == MONOMORPHIC);
-
// The number of monomorphic stubs for normal load/store/call IC's can grow to
// a large number and therefore they need to go into a hash table. They are
// used to load global properties from cells.
@@ -6098,6 +6096,29 @@
}
+void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
+ // Disable optimization for the shared function info and mark the
+ // code as non-optimizable. The marker on the shared function info
+ // is there because we flush non-optimized code thereby loosing the
+ // non-optimizable information for the code. When the code is
+ // regenerated and set on the shared function info it is marked as
+ // non-optimizable if optimization is disabled for the shared
+ // function info.
+ set_optimization_disabled(true);
+ // Code should be the lazy compilation stub or else unoptimized. If the
+ // latter, disable optimization for the code too.
+ ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
+ if (code()->kind() == Code::FUNCTION) {
+ code()->set_optimizable(false);
+ }
+ if (FLAG_trace_opt) {
+ PrintF("[disabled optimization for: ");
+ function->PrintName();
+ PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
+ }
+}
+
+
bool SharedFunctionInfo::VerifyBailoutId(int id) {
// TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
// we are always bailing out on ARM.
@@ -6555,10 +6576,8 @@
case BUILTIN: return "BUILTIN";
case LOAD_IC: return "LOAD_IC";
case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
- case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
case STORE_IC: return "STORE_IC";
case KEYED_STORE_IC: return "KEYED_STORE_IC";
- case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
case CALL_IC: return "CALL_IC";
case KEYED_CALL_IC: return "KEYED_CALL_IC";
case TYPE_RECORDING_UNARY_OP_IC: return "TYPE_RECORDING_UNARY_OP_IC";
@@ -7331,7 +7350,7 @@
uint32_t index,
Object* holder) {
Isolate* isolate = GetIsolate();
- ASSERT(!structure->IsProxy());
+ ASSERT(!structure->IsForeign());
// api style callbacks.
if (structure->IsAccessorInfo()) {
@@ -7386,9 +7405,9 @@
Handle<Object> value_handle(value, isolate);
// To accommodate both the old and the new api we switch on the
- // data structure used to store the callbacks. Eventually proxy
+ // data structure used to store the callbacks. Eventually foreign
// callbacks should be phased out.
- ASSERT(!structure->IsProxy());
+ ASSERT(!structure->IsForeign());
if (structure->IsAccessorInfo()) {
// api style callbacks
diff --git a/src/objects.h b/src/objects.h
index e68ac53..b511213 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -30,6 +30,7 @@
#include "allocation.h"
#include "builtins.h"
+#include "list.h"
#include "smart-pointer.h"
#include "unicode-inl.h"
#if V8_TARGET_ARCH_ARM
@@ -91,7 +92,7 @@
// - Map
// - Oddball
// - JSProxy
-// - Proxy
+// - Foreign
// - SharedFunctionInfo
// - Struct
// - AccessorInfo
@@ -289,7 +290,7 @@
\
V(HEAP_NUMBER_TYPE) \
V(JS_PROXY_TYPE) \
- V(PROXY_TYPE) \
+ V(FOREIGN_TYPE) \
V(BYTE_ARRAY_TYPE) \
/* Note: the order of these external array */ \
/* types is relied upon in */ \
@@ -516,7 +517,7 @@
// "Data", objects that cannot contain non-map-word pointers to heap
// objects.
HEAP_NUMBER_TYPE,
- PROXY_TYPE,
+ FOREIGN_TYPE,
JS_PROXY_TYPE,
BYTE_ARRAY_TYPE,
EXTERNAL_BYTE_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
@@ -590,7 +591,7 @@
STATIC_CHECK(JS_OBJECT_TYPE == Internals::kJSObjectType);
STATIC_CHECK(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
-STATIC_CHECK(PROXY_TYPE == Internals::kProxyType);
+STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType);
enum CompareResult {
@@ -628,6 +629,7 @@
// A template-ized version of the IsXXX functions.
template <class C> static inline bool Is(Object* obj);
+class Failure;
class MaybeObject BASE_EMBEDDED {
public:
@@ -641,6 +643,10 @@
*obj = reinterpret_cast<Object*>(this);
return true;
}
+ inline Failure* ToFailureUnchecked() {
+ ASSERT(IsFailure());
+ return reinterpret_cast<Failure*>(this);
+ }
inline Object* ToObjectUnchecked() {
ASSERT(!IsFailure());
return reinterpret_cast<Object*>(this);
@@ -720,7 +726,7 @@
V(JSValue) \
V(JSMessageObject) \
V(StringWrapper) \
- V(Proxy) \
+ V(Foreign) \
V(Boolean) \
V(JSArray) \
V(JSProxy) \
@@ -3275,12 +3281,10 @@
BUILTIN,
LOAD_IC,
KEYED_LOAD_IC,
- KEYED_EXTERNAL_ARRAY_LOAD_IC,
CALL_IC,
KEYED_CALL_IC,
STORE_IC,
KEYED_STORE_IC,
- KEYED_EXTERNAL_ARRAY_STORE_IC,
TYPE_RECORDING_UNARY_OP_IC,
TYPE_RECORDING_BINARY_OP_IC,
COMPARE_IC,
@@ -3363,12 +3367,6 @@
return kind() == TYPE_RECORDING_BINARY_OP_IC;
}
inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; }
- inline bool is_external_array_load_stub() {
- return kind() == KEYED_EXTERNAL_ARRAY_LOAD_IC;
- }
- inline bool is_external_array_store_stub() {
- return kind() == KEYED_EXTERNAL_ARRAY_STORE_IC;
- }
// [major_key]: For kind STUB or BINARY_OP_IC, the major key.
inline int major_key();
@@ -4011,7 +4009,7 @@
DECL_ACCESSORS(context_data, Object)
// [wrapper]: the wrapper cache.
- DECL_ACCESSORS(wrapper, Proxy)
+ DECL_ACCESSORS(wrapper, Foreign)
// [type]: the script type.
DECL_ACCESSORS(type, Smi)
@@ -4370,6 +4368,11 @@
// Enable deoptimization support through recompiled code.
void EnableDeoptimizationSupport(Code* recompiled);
+ // Disable (further) attempted optimization of all functions sharing this
+ // shared function info. The function is the one we actually tried to
+ // optimize.
+ void DisableOptimization(JSFunction* function);
+
// Lookup the bailout ID and ASSERT that it exists in the non-optimized
// code, returns whether it asserted (i.e., always true if assertions are
// disabled).
@@ -4751,7 +4754,7 @@
class JSGlobalProxy : public JSObject {
public:
- // [context]: the owner global context of this proxy object.
+ // [context]: the owner global context of this global proxy object.
// It is null value if this object is not used by any context.
DECL_ACCESSORS(context, Object)
@@ -6144,43 +6147,43 @@
-// Proxy describes objects pointing from JavaScript to C structures.
+// Foreign describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space.
-class Proxy: public HeapObject {
+class Foreign: public HeapObject {
public:
- // [proxy]: field containing the address.
- inline Address proxy();
- inline void set_proxy(Address value);
+ // [address]: field containing the address.
+ inline Address address();
+ inline void set_address(Address value);
// Casting.
- static inline Proxy* cast(Object* obj);
+ static inline Foreign* cast(Object* obj);
// Dispatched behavior.
- inline void ProxyIterateBody(ObjectVisitor* v);
+ inline void ForeignIterateBody(ObjectVisitor* v);
template<typename StaticVisitor>
- inline void ProxyIterateBody();
+ inline void ForeignIterateBody();
#ifdef OBJECT_PRINT
- inline void ProxyPrint() {
- ProxyPrint(stdout);
+ inline void ForeignPrint() {
+ ForeignPrint(stdout);
}
- void ProxyPrint(FILE* out);
+ void ForeignPrint(FILE* out);
#endif
#ifdef DEBUG
- void ProxyVerify();
+ void ForeignVerify();
#endif
// Layout description.
- static const int kProxyOffset = HeapObject::kHeaderSize;
- static const int kSize = kProxyOffset + kPointerSize;
+ static const int kAddressOffset = HeapObject::kHeaderSize;
+ static const int kSize = kAddressOffset + kPointerSize;
- STATIC_CHECK(kProxyOffset == Internals::kProxyProxyOffset);
+ STATIC_CHECK(kAddressOffset == Internals::kForeignAddressOffset);
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(Proxy);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Foreign);
};
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index e65734b..98c343e 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -74,7 +74,7 @@
function_store_.Add((arg_opt == NULL) ? 0 : 1);
STATIC_ASSERT(PreparseDataConstants::kMessageTextPos == 3);
WriteString(CStrVector(message));
- if (arg_opt) WriteString(CStrVector(arg_opt));
+ if (arg_opt != NULL) WriteString(CStrVector(arg_opt));
is_recording_ = false;
}
diff --git a/src/preparser.cc b/src/preparser.cc
index 5bd9906..3c48d14 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -1,4 +1,4 @@
-// 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:
@@ -56,13 +56,6 @@
namespace i = ::v8::internal;
-#define CHECK_OK ok); \
- if (!*ok) return -1; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-
void PreParser::ReportUnexpectedToken(i::Token::Value token) {
// We don't report stack overflows here, to avoid increasing the
// stack depth even further. Instead we report it after parsing is
@@ -107,6 +100,13 @@
}
+#define CHECK_OK ok); \
+ if (!*ok) return kUnknownSourceElements; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
+
PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
bool* ok) {
// SourceElements ::
@@ -116,9 +116,9 @@
while (peek() != end_token) {
Statement statement = ParseStatement(CHECK_OK);
if (allow_directive_prologue) {
- if (statement == kUseStrictExpressionStatement) {
+ if (statement.IsUseStrictLiteral()) {
set_strict_mode();
- } else if (statement != kStringLiteralExpressionStatement) {
+ } else if (!statement.IsStringLiteral()) {
allow_directive_prologue = false;
}
}
@@ -127,6 +127,14 @@
}
+#undef CHECK_OK
+#define CHECK_OK ok); \
+ if (!*ok) return Statement::Default(); \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
+
PreParser::Statement PreParser::ParseStatement(bool* ok) {
// Statement ::
// Block
@@ -163,10 +171,10 @@
case i::Token::SEMICOLON:
Next();
- return kUnknownStatement;
+ return Statement::Default();
case i::Token::IF:
- return ParseIfStatement(ok);
+ return ParseIfStatement(ok);
case i::Token::DO:
return ParseDoWhileStatement(ok);
@@ -217,9 +225,24 @@
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
Expect(i::Token::FUNCTION, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- ParseFunctionLiteral(CHECK_OK);
- return kUnknownStatement;
+
+ Identifier identifier = ParseIdentifier(CHECK_OK);
+ i::Scanner::Location location = scanner_->location();
+
+ Expression function_value = ParseFunctionLiteral(CHECK_OK);
+
+ if (function_value.IsStrictFunction() &&
+ !identifier.IsValidStrictVariable()) {
+ // Strict mode violation, using either reserved word or eval/arguments
+ // as name of strict function.
+ const char* type = "strict_function_name";
+ if (identifier.IsFutureReserved()) {
+ type = "strict_reserved_word";
+ }
+ ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ *ok = false;
+ }
+ return Statement::Default();
}
@@ -242,7 +265,7 @@
}
Expect(i::Token::RPAREN, CHECK_OK);
Expect(i::Token::SEMICOLON, CHECK_OK);
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -257,8 +280,8 @@
while (peek() != i::Token::RBRACE) {
ParseStatement(CHECK_OK);
}
- Expect(i::Token::RBRACE, CHECK_OK);
- return kUnknownStatement;
+ Expect(i::Token::RBRACE, ok);
+ return Statement::Default();
}
@@ -289,7 +312,7 @@
Consume(i::Token::CONST);
} else {
*ok = false;
- return 0;
+ return Statement::Default();
}
// The scope of a variable/const declared anywhere inside a function
@@ -298,7 +321,14 @@
do {
// Parse variable name.
if (nvars > 0) Consume(i::Token::COMMA);
- ParseIdentifier(CHECK_OK);
+ Identifier identifier = ParseIdentifier(CHECK_OK);
+ if (strict_mode() && !identifier.IsValidStrictVariable()) {
+ StrictModeIdentifierViolation(scanner_->location(),
+ "strict_var_name",
+ identifier,
+ ok);
+ return Statement::Default();
+ }
nvars++;
if (peek() == i::Token::ASSIGN) {
Expect(i::Token::ASSIGN, CHECK_OK);
@@ -307,31 +337,24 @@
} while (peek() == i::Token::COMMA);
if (num_decl != NULL) *num_decl = nvars;
- return kUnknownStatement;
+ return Statement::Default();
}
-PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
- bool* ok) {
+PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
// ExpressionStatement | LabelledStatement ::
// Expression ';'
// Identifier ':' Statement
Expression expr = ParseExpression(true, CHECK_OK);
- if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
+ if (peek() == i::Token::COLON && expr.IsRawIdentifier()) {
Consume(i::Token::COLON);
ParseStatement(ok);
- return kUnknownStatement;
+ return Statement::Default();
}
// Parsed expression statement.
ExpectSemicolon(CHECK_OK);
- if (expr == kStringLiteralExpression) {
- return kStringLiteralExpressionStatement;
- }
- if (expr == kUseStrictString) {
- return kUseStrictExpressionStatement;
- }
- return kUnknownStatement;
+ return Statement::ExpressionStatement(expr);
}
@@ -348,7 +371,7 @@
Next();
ParseStatement(CHECK_OK);
}
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -365,7 +388,7 @@
ParseIdentifier(CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -382,7 +405,7 @@
ParseIdentifier(CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -408,7 +431,7 @@
ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -416,6 +439,13 @@
// WithStatement ::
// 'with' '(' Expression ')' Statement
Expect(i::Token::WITH, CHECK_OK);
+ if (strict_mode()) {
+ i::Scanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "strict_mode_with", NULL);
+ *ok = false;
+ return Statement::Default();
+ }
Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK);
@@ -423,7 +453,7 @@
scope_->EnterWith();
ParseStatement(CHECK_OK);
scope_->LeaveWith();
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -451,9 +481,8 @@
}
token = peek();
}
- Expect(i::Token::RBRACE, CHECK_OK);
-
- return kUnknownStatement;
+ Expect(i::Token::RBRACE, ok);
+ return Statement::Default();
}
@@ -466,8 +495,8 @@
Expect(i::Token::WHILE, CHECK_OK);
Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- return kUnknownStatement;
+ Expect(i::Token::RPAREN, ok);
+ return Statement::Default();
}
@@ -479,8 +508,8 @@
Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
+ ParseStatement(ok);
+ return Statement::Default();
}
@@ -500,7 +529,7 @@
Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
- return kUnknownStatement;
+ return Statement::Default();
}
} else {
ParseExpression(false, CHECK_OK);
@@ -510,7 +539,7 @@
Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
- return kUnknownStatement;
+ return Statement::Default();
}
}
}
@@ -528,8 +557,8 @@
}
Expect(i::Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
+ ParseStatement(ok);
+ return Statement::Default();
}
@@ -543,12 +572,11 @@
ReportMessageAt(pos.beg_pos, pos.end_pos,
"newline_after_throw", NULL);
*ok = false;
- return kUnknownStatement;
+ return Statement::Default();
}
ParseExpression(true, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
-
- return kUnknownStatement;
+ ExpectSemicolon(ok);
+ return Statement::Default();
}
@@ -575,12 +603,19 @@
if (peek() == i::Token::CATCH) {
Consume(i::Token::CATCH);
Expect(i::Token::LPAREN, CHECK_OK);
- ParseIdentifier(CHECK_OK);
+ Identifier id = ParseIdentifier(CHECK_OK);
+ if (strict_mode() && !id.IsValidStrictVariable()) {
+ StrictModeIdentifierViolation(scanner_->location(),
+ "strict_catch_variable",
+ id,
+ ok);
+ return Statement::Default();
+ }
Expect(i::Token::RPAREN, CHECK_OK);
scope_->EnterWith();
ParseBlock(ok);
scope_->LeaveWith();
- if (!*ok) return kUnknownStatement;
+ if (!*ok) Statement::Default();
catch_or_finally_seen = true;
}
if (peek() == i::Token::FINALLY) {
@@ -591,7 +626,7 @@
if (!catch_or_finally_seen) {
*ok = false;
}
- return kUnknownStatement;
+ return Statement::Default();
}
@@ -603,11 +638,19 @@
// 'debugger' ';'
Expect(i::Token::DEBUGGER, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
+ ExpectSemicolon(ok);
+ return Statement::Default();
}
+#undef CHECK_OK
+#define CHECK_OK ok); \
+ if (!*ok) return Expression::Default(); \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
+
// Precedence = 1
PreParser::Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
// Expression ::
@@ -618,7 +661,7 @@
while (peek() == i::Token::COMMA) {
Expect(i::Token::COMMA, CHECK_OK);
ParseAssignmentExpression(accept_IN, CHECK_OK);
- result = kUnknownExpression;
+ result = Expression::Default();
}
return result;
}
@@ -631,6 +674,7 @@
// ConditionalExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
+ i::Scanner::Location before = scanner_->peek_location();
Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
if (!i::Token::IsAssignmentOp(peek())) {
@@ -638,14 +682,23 @@
return expression;
}
+ if (strict_mode() && expression.IsIdentifier() &&
+ expression.AsIdentifier().IsEvalOrArguments()) {
+ i::Scanner::Location after = scanner_->location();
+ ReportMessageAt(before.beg_pos, after.end_pos,
+ "strict_lhs_assignment", NULL);
+ *ok = false;
+ return Expression::Default();
+ }
+
i::Token::Value op = Next(); // Get assignment operator.
ParseAssignmentExpression(accept_IN, CHECK_OK);
- if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
+ if ((op == i::Token::ASSIGN) && expression.IsThisProperty()) {
scope_->AddProperty();
}
- return kUnknownExpression;
+ return Expression::Default();
}
@@ -666,7 +719,7 @@
ParseAssignmentExpression(true, CHECK_OK);
Expect(i::Token::COLON, CHECK_OK);
ParseAssignmentExpression(accept_IN, CHECK_OK);
- return kUnknownExpression;
+ return Expression::Default();
}
@@ -688,7 +741,7 @@
while (Precedence(peek(), accept_IN) == prec1) {
Next();
ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
- result = kUnknownExpression;
+ result = Expression::Default();
}
}
return result;
@@ -709,10 +762,22 @@
// '!' UnaryExpression
i::Token::Value op = peek();
- if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
+ if (i::Token::IsUnaryOp(op)) {
op = Next();
ParseUnaryExpression(ok);
- return kUnknownExpression;
+ return Expression::Default();
+ } else if (i::Token::IsCountOp(op)) {
+ op = Next();
+ i::Scanner::Location before = scanner_->peek_location();
+ Expression expression = ParseUnaryExpression(CHECK_OK);
+ if (strict_mode() && expression.IsIdentifier() &&
+ expression.AsIdentifier().IsEvalOrArguments()) {
+ i::Scanner::Location after = scanner_->location();
+ ReportMessageAt(before.beg_pos, after.end_pos,
+ "strict_lhs_prefix", NULL);
+ *ok = false;
+ }
+ return Expression::Default();
} else {
return ParsePostfixExpression(ok);
}
@@ -723,11 +788,20 @@
// PostfixExpression ::
// LeftHandSideExpression ('++' | '--')?
+ i::Scanner::Location before = scanner_->peek_location();
Expression expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner_->has_line_terminator_before_next() &&
i::Token::IsCountOp(peek())) {
+ if (strict_mode() && expression.IsIdentifier() &&
+ expression.AsIdentifier().IsEvalOrArguments()) {
+ i::Scanner::Location after = scanner_->location();
+ ReportMessageAt(before.beg_pos, after.end_pos,
+ "strict_lhs_postfix", NULL);
+ *ok = false;
+ return Expression::Default();
+ }
Next();
- return kUnknownExpression;
+ return Expression::Default();
}
return expression;
}
@@ -737,7 +811,7 @@
// LeftHandSideExpression ::
// (NewExpression | MemberExpression) ...
- Expression result;
+ Expression result = Expression::Default();
if (peek() == i::Token::NEW) {
result = ParseNewExpression(CHECK_OK);
} else {
@@ -750,27 +824,27 @@
Consume(i::Token::LBRACK);
ParseExpression(true, CHECK_OK);
Expect(i::Token::RBRACK, CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
+ if (result.IsThis()) {
+ result = Expression::ThisProperty();
} else {
- result = kUnknownExpression;
+ result = Expression::Default();
}
break;
}
case i::Token::LPAREN: {
ParseArguments(CHECK_OK);
- result = kUnknownExpression;
+ result = Expression::Default();
break;
}
case i::Token::PERIOD: {
Consume(i::Token::PERIOD);
ParseIdentifierName(CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
+ if (result.IsThis()) {
+ result = Expression::ThisProperty();
} else {
- result = kUnknownExpression;
+ result = Expression::Default();
}
break;
}
@@ -816,13 +890,21 @@
// ('[' Expression ']' | '.' Identifier | Arguments)*
// Parse the initial primary or function expression.
- Expression result = kUnknownExpression;
+ Expression result = Expression::Default();
if (peek() == i::Token::FUNCTION) {
Consume(i::Token::FUNCTION);
+ Identifier identifier = Identifier::Default();
if (peek_any_identifier()) {
- ParseIdentifier(CHECK_OK);
+ identifier = ParseIdentifier(CHECK_OK);
}
result = ParseFunctionLiteral(CHECK_OK);
+ if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
+ StrictModeIdentifierViolation(scanner_->location(),
+ "strict_function_name",
+ identifier,
+ ok);
+ return Expression::Default();
+ }
} else {
result = ParsePrimaryExpression(CHECK_OK);
}
@@ -833,20 +915,20 @@
Consume(i::Token::LBRACK);
ParseExpression(true, CHECK_OK);
Expect(i::Token::RBRACK, CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
+ if (result.IsThis()) {
+ result = Expression::ThisProperty();
} else {
- result = kUnknownExpression;
+ result = Expression::Default();
}
break;
}
case i::Token::PERIOD: {
Consume(i::Token::PERIOD);
ParseIdentifierName(CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
+ if (result.IsThis()) {
+ result = Expression::ThisProperty();
} else {
- result = kUnknownExpression;
+ result = Expression::Default();
}
break;
}
@@ -855,7 +937,7 @@
// Consume one of the new prefixes (already parsed).
ParseArguments(CHECK_OK);
new_count--;
- result = kUnknownExpression;
+ result = Expression::Default();
break;
}
default:
@@ -879,18 +961,27 @@
// RegExpLiteral
// '(' Expression ')'
- Expression result = kUnknownExpression;
+ Expression result = Expression::Default();
switch (peek()) {
case i::Token::THIS: {
Next();
- result = kThisExpression;
+ result = Expression::This();
break;
}
- case i::Token::IDENTIFIER:
- case i::Token::FUTURE_RESERVED_WORD: {
- ParseIdentifier(CHECK_OK);
- result = kIdentifierExpression;
+ case i::Token::FUTURE_RESERVED_WORD:
+ if (strict_mode()) {
+ Next();
+ i::Scanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "strict_reserved_word", NULL);
+ *ok = false;
+ return Expression::Default();
+ }
+ // FALLTHROUGH
+ case i::Token::IDENTIFIER: {
+ Identifier id = ParseIdentifier(CHECK_OK);
+ result = Expression::FromIdentifier(id);
break;
}
@@ -928,7 +1019,7 @@
parenthesized_function_ = (peek() == i::Token::FUNCTION);
result = ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK);
- if (result == kIdentifierExpression) result = kUnknownExpression;
+ result = result.Parenthesize();
break;
case i::Token::MOD:
@@ -938,7 +1029,7 @@
default: {
Next();
*ok = false;
- return kUnknownExpression;
+ return Expression::Default();
}
}
@@ -961,7 +1052,7 @@
Expect(i::Token::RBRACK, CHECK_OK);
scope_->NextMaterializedLiteralIndex();
- return kUnknownExpression;
+ return Expression::Default();
}
@@ -990,7 +1081,7 @@
name != i::Token::STRING &&
!is_keyword) {
*ok = false;
- return kUnknownExpression;
+ return Expression::Default();
}
if (!is_keyword) {
LogSymbol();
@@ -1016,7 +1107,7 @@
} else {
// Unexpected token.
*ok = false;
- return kUnknownExpression;
+ return Expression::Default();
}
}
@@ -1029,7 +1120,7 @@
Expect(i::Token::RBRACE, CHECK_OK);
scope_->NextMaterializedLiteralIndex();
- return kUnknownExpression;
+ return Expression::Default();
}
@@ -1041,7 +1132,7 @@
ReportMessageAt(location.beg_pos, location.end_pos,
"unterminated_regexp", NULL);
*ok = false;
- return kUnknownExpression;
+ return Expression::Default();
}
scope_->NextMaterializedLiteralIndex();
@@ -1052,10 +1143,10 @@
ReportMessageAt(location.beg_pos, location.end_pos,
"invalid_regexp_flags", NULL);
*ok = false;
- return kUnknownExpression;
+ return Expression::Default();
}
Next();
- return kUnknownExpression;
+ return Expression::Default();
}
@@ -1063,16 +1154,21 @@
// Arguments ::
// '(' (AssignmentExpression)*[','] ')'
- Expect(i::Token::LPAREN, CHECK_OK);
+ Expect(i::Token::LPAREN, ok);
+ if (!*ok) return -1;
bool done = (peek() == i::Token::RPAREN);
int argc = 0;
while (!done) {
- ParseAssignmentExpression(true, CHECK_OK);
+ ParseAssignmentExpression(true, ok);
+ if (!*ok) return -1;
argc++;
done = (peek() == i::Token::RPAREN);
- if (!done) Expect(i::Token::COMMA, CHECK_OK);
+ if (!done) {
+ Expect(i::Token::COMMA, ok);
+ if (!*ok) return -1;
+ }
}
- Expect(i::Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, ok);
return argc;
}
@@ -1091,7 +1187,13 @@
int start_position = scanner_->location().beg_pos;
bool done = (peek() == i::Token::RPAREN);
while (!done) {
- ParseIdentifier(CHECK_OK);
+ Identifier id = ParseIdentifier(CHECK_OK);
+ if (!id.IsValidStrictVariable()) {
+ StrictModeIdentifierViolation(scanner_->location(),
+ "strict_param_name",
+ id,
+ CHECK_OK);
+ }
done = (peek() == i::Token::RPAREN);
if (!done) {
Expect(i::Token::COMMA, CHECK_OK);
@@ -1114,7 +1216,7 @@
log_->PauseRecording();
ParseSourceElements(i::Token::RBRACE, ok);
log_->ResumeRecording();
- if (!*ok) return kUnknownExpression;
+ if (!*ok) Expression::Default();
Expect(i::Token::RBRACE, CHECK_OK);
@@ -1128,12 +1230,14 @@
Expect(i::Token::RBRACE, CHECK_OK);
}
- if (scope_->is_strict()) {
+ if (strict_mode()) {
int end_position = scanner_->location().end_pos;
CheckOctalLiteral(start_position, end_position, CHECK_OK);
+ CheckDelayedStrictModeViolation(start_position, end_position, CHECK_OK);
+ return Expression::StrictFunction();
}
- return kUnknownExpression;
+ return Expression::Default();
}
@@ -1143,11 +1247,13 @@
Expect(i::Token::MOD, CHECK_OK);
ParseIdentifier(CHECK_OK);
- ParseArguments(CHECK_OK);
+ ParseArguments(ok);
- return kUnknownExpression;
+ return Expression::Default();
}
+#undef CHECK_OK
+
void PreParser::ExpectSemicolon(bool* ok) {
// Check for automatic semicolon insertion according to
@@ -1176,12 +1282,6 @@
}
-PreParser::Identifier PreParser::GetIdentifierSymbol() {
- LogSymbol();
- return kUnknownIdentifier;
-}
-
-
PreParser::Expression PreParser::GetStringSymbol() {
const int kUseStrictLength = 10;
const char* kUseStrictChars = "use strict";
@@ -1191,21 +1291,89 @@
!scanner_->literal_contains_escapes() &&
!strncmp(scanner_->literal_ascii_string().start(), kUseStrictChars,
kUseStrictLength)) {
- return kUseStrictString;
+ return Expression::UseStrictStringLiteral();
}
- return kStringLiteralExpression;
+ return Expression::StringLiteral();
+}
+
+
+PreParser::Identifier PreParser::GetIdentifierSymbol() {
+ LogSymbol();
+ if (scanner_->current_token() == i::Token::FUTURE_RESERVED_WORD) {
+ return Identifier::FutureReserved();
+ }
+ if (scanner_->is_literal_ascii()) {
+ // Detect strict-mode poison words.
+ if (scanner_->literal_length() == 4 &&
+ !strncmp(scanner_->literal_ascii_string().start(), "eval", 4)) {
+ return Identifier::Eval();
+ }
+ if (scanner_->literal_length() == 9 &&
+ !strncmp(scanner_->literal_ascii_string().start(), "arguments", 9)) {
+ return Identifier::Arguments();
+ }
+ }
+ return Identifier::Default();
}
PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
if (!Check(i::Token::FUTURE_RESERVED_WORD)) {
Expect(i::Token::IDENTIFIER, ok);
+ if (!*ok) return Identifier::Default();
}
- if (!*ok) return kUnknownIdentifier;
return GetIdentifierSymbol();
}
+void PreParser::SetStrictModeViolation(i::Scanner::Location location,
+ const char* type,
+ bool* ok) {
+ if (strict_mode()) {
+ ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ *ok = false;
+ return;
+ }
+ // Delay report in case this later turns out to be strict code
+ // (i.e., for function names and parameters prior to a "use strict"
+ // directive).
+ strict_mode_violation_location_ = location;
+ strict_mode_violation_type_ = type;
+}
+
+
+void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
+ int end_pos,
+ bool* ok) {
+ i::Scanner::Location location = strict_mode_violation_location_;
+ if (location.IsValid() &&
+ location.beg_pos > beg_pos && location.end_pos < end_pos) {
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ strict_mode_violation_type_, NULL);
+ *ok = false;
+ }
+ strict_mode_violation_location_ = i::Scanner::Location::invalid();
+}
+
+
+void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
+ const char* eval_args_type,
+ Identifier identifier,
+ bool* ok) {
+ const char* type = eval_args_type;
+ if (identifier.IsFutureReserved()) {
+ type = "strict_reserved_word";
+ }
+ if (strict_mode()) {
+ ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ *ok = false;
+ return;
+ }
+ strict_mode_violation_location_ = location;
+ strict_mode_violation_type_ = type;
+}
+
+
PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
i::Token::Value next = Next();
if (i::Token::IsKeyword(next)) {
@@ -1213,24 +1381,28 @@
const char* keyword = i::Token::String(next);
log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword,
i::StrLength(keyword)));
- return kUnknownExpression;
+ return Identifier::Default();
}
if (next == i::Token::IDENTIFIER ||
next == i::Token::FUTURE_RESERVED_WORD) {
return GetIdentifierSymbol();
}
*ok = false;
- return kUnknownIdentifier;
+ return Identifier::Default();
}
+#undef CHECK_OK
+
// This function reads an identifier and determines whether or not it
// is 'get' or 'set'.
PreParser::Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
bool* is_set,
bool* ok) {
- PreParser::Identifier result = ParseIdentifier(CHECK_OK);
- if (scanner_->is_literal_ascii() && scanner_->literal_length() == 3) {
+ Identifier result = ParseIdentifier(ok);
+ if (!*ok) return Identifier::Default();
+ if (scanner_->is_literal_ascii() &&
+ scanner_->literal_length() == 3) {
const char* token = scanner_->literal_ascii_string().start();
*is_get = strncmp(token, "get", 3) == 0;
*is_set = !*is_get && strncmp(token, "set", 3) == 0;
@@ -1243,6 +1415,4 @@
return next == i::Token::IDENTIFIER ||
next == i::Token::FUTURE_RESERVED_WORD;
}
-
-#undef CHECK_OK
} } // v8::preparser
diff --git a/src/preparser.h b/src/preparser.h
index 93a8a42..2a2a49a 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -1,4 +1,4 @@
-// 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:
@@ -67,47 +67,217 @@
}
private:
+ // These types form an algebra over syntactic categories that is just
+ // rich enough to let us recognize and propagate the constructs that
+ // are either being counted in the preparser data, or is important
+ // to throw the correct syntax error exceptions.
+
enum ScopeType {
kTopLevelScope,
kFunctionScope
};
- // Types that allow us to recognize simple this-property assignments.
- // A simple this-property assignment is a statement on the form
- // "this.propertyName = {primitive constant or function parameter name);"
- // where propertyName isn't "__proto__".
- // The result is only relevant if the function body contains only
- // simple this-property assignments.
+ class Expression;
- enum StatementType {
- kUnknownStatement,
- kStringLiteralExpressionStatement,
- kUseStrictExpressionStatement
+ class Identifier {
+ public:
+ static Identifier Default() {
+ return Identifier(kUnknownIdentifier);
+ }
+ static Identifier Eval() {
+ return Identifier(kEvalIdentifier);
+ }
+ static Identifier Arguments() {
+ return Identifier(kArgumentsIdentifier);
+ }
+ static Identifier FutureReserved() {
+ return Identifier(kFutureReservedIdentifier);
+ }
+ bool IsEval() { return type_ == kEvalIdentifier; }
+ bool IsArguments() { return type_ == kArgumentsIdentifier; }
+ bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; }
+ bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; }
+ bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; }
+ private:
+ enum Type {
+ kUnknownIdentifier,
+ kFutureReservedIdentifier,
+ kEvalIdentifier,
+ kArgumentsIdentifier
+ };
+ explicit Identifier(Type type) : type_(type) { }
+ Type type_;
+
+ friend class Expression;
};
- enum ExpressionType {
- kUnknownExpression,
- kIdentifierExpression, // Used to detect labels.
- kThisExpression,
- kThisPropertyExpression,
- kStringLiteralExpression,
- kUseStrictString
+ // Bits 0 and 1 are used to identify the type of expression:
+ // If bit 0 is set, it's an identifier.
+ // if bit 1 is set, it's a string literal.
+ // If neither is set, it's no particular type, and both set isn't
+ // use yet.
+ // Bit 2 is used to mark the expression as being parenthesized,
+ // so "(foo)" isn't recognized as a pure identifier (and possible label).
+ class Expression {
+ public:
+ static Expression Default() {
+ return Expression(kUnknownExpression);
+ }
+
+ static Expression FromIdentifier(Identifier id) {
+ return Expression(kIdentifierFlag | (id.type_ << kIdentifierShift));
+ }
+
+ static Expression StringLiteral() {
+ return Expression(kUnknownStringLiteral);
+ }
+
+ static Expression UseStrictStringLiteral() {
+ return Expression(kUseStrictString);
+ }
+
+ static Expression This() {
+ return Expression(kThisExpression);
+ }
+
+ static Expression ThisProperty() {
+ return Expression(kThisPropertyExpression);
+ }
+
+ static Expression StrictFunction() {
+ return Expression(kStrictFunctionExpression);
+ }
+
+ bool IsIdentifier() {
+ return (code_ & kIdentifierFlag) != 0;
+ }
+
+ // Only works corretly if it is actually an identifier expression.
+ PreParser::Identifier AsIdentifier() {
+ return PreParser::Identifier(
+ static_cast<PreParser::Identifier::Type>(code_ >> kIdentifierShift));
+ }
+
+ bool IsParenthesized() {
+ // If bit 0 or 1 is set, we interpret bit 2 as meaning parenthesized.
+ return (code_ & 7) > 4;
+ }
+
+ bool IsRawIdentifier() {
+ return !IsParenthesized() && IsIdentifier();
+ }
+
+ bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; }
+
+ bool IsRawStringLiteral() {
+ return !IsParenthesized() && IsStringLiteral();
+ }
+
+ bool IsUseStrictLiteral() {
+ return (code_ & kStringLiteralMask) == kUseStrictString;
+ }
+
+ bool IsThis() {
+ return code_ == kThisExpression;
+ }
+
+ bool IsThisProperty() {
+ return code_ == kThisPropertyExpression;
+ }
+
+ bool IsStrictFunction() {
+ return code_ == kStrictFunctionExpression;
+ }
+
+ Expression Parenthesize() {
+ int type = code_ & 3;
+ if (type != 0) {
+ // Identifiers and string literals can be parenthesized.
+ // They no longer work as labels or directive prologues,
+ // but are still recognized in other contexts.
+ return Expression(code_ | kParentesizedExpressionFlag);
+ }
+ // For other types of expressions, it's not important to remember
+ // the parentheses.
+ return *this;
+ }
+
+ private:
+ // First two/three bits are used as flags.
+ // Bit 0 and 1 represent identifiers or strings literals, and are
+ // mutually exclusive, but can both be absent.
+ // If bit 0 or 1 are set, bit 2 marks that the expression has
+ // been wrapped in parentheses (a string literal can no longer
+ // be a directive prologue, and an identifier can no longer be
+ // a label.
+ enum {
+ kUnknownExpression = 0,
+ // Identifiers
+ kIdentifierFlag = 1, // Used to detect labels.
+ kIdentifierShift = 3,
+
+ kStringLiteralFlag = 2, // Used to detect directive prologue.
+ kUnknownStringLiteral = kStringLiteralFlag,
+ kUseStrictString = kStringLiteralFlag | 8,
+ kStringLiteralMask = kUseStrictString,
+
+ kParentesizedExpressionFlag = 4, // Only if identifier or string literal.
+
+ // Below here applies if neither identifier nor string literal.
+ kThisExpression = 4,
+ kThisPropertyExpression = 8,
+ kStrictFunctionExpression = 12
+ };
+
+ explicit Expression(int expression_code) : code_(expression_code) { }
+
+ int code_;
};
- enum IdentifierType {
- kUnknownIdentifier
+ class Statement {
+ public:
+ static Statement Default() {
+ return Statement(kUnknownStatement);
+ }
+
+ // Creates expression statement from expression.
+ // Preserves being an unparenthesized string literal, possibly
+ // "use strict".
+ static Statement ExpressionStatement(Expression expression) {
+ if (!expression.IsParenthesized()) {
+ if (expression.IsUseStrictLiteral()) {
+ return Statement(kUseStrictExpressionStatement);
+ }
+ if (expression.IsStringLiteral()) {
+ return Statement(kStringLiteralExpressionStatement);
+ }
+ }
+ return Default();
+ }
+
+ bool IsStringLiteral() {
+ return code_ != kUnknownStatement;
+ }
+
+ bool IsUseStrictLiteral() {
+ return code_ == kUseStrictExpressionStatement;
+ }
+
+ private:
+ enum Type {
+ kUnknownStatement,
+ kStringLiteralExpressionStatement,
+ kUseStrictExpressionStatement
+ };
+
+ explicit Statement(Type code) : code_(code) {}
+ Type code_;
};
- enum SourceElementTypes {
- kUnknownSourceElements,
- kDirectivePrologue,
- kUseStrictDirective
+ enum SourceElements {
+ kUnknownSourceElements
};
- typedef int SourceElements;
- typedef int Expression;
- typedef int Statement;
- typedef int Identifier;
typedef int Arguments;
class Scope {
@@ -153,6 +323,8 @@
log_(log),
scope_(NULL),
stack_limit_(stack_limit),
+ strict_mode_violation_location_(i::Scanner::Location::invalid()),
+ strict_mode_violation_type_(NULL),
stack_overflow_(false),
allow_lazy_(true),
parenthesized_function_(false) { }
@@ -264,7 +436,7 @@
scope_->set_strict();
}
- bool is_strict_mode() { return scope_->is_strict(); }
+ bool strict_mode() { return scope_->is_strict(); }
void Consume(i::Token::Value token) { Next(); }
@@ -286,10 +458,23 @@
static int Precedence(i::Token::Value tok, bool accept_IN);
+ void SetStrictModeViolation(i::Scanner::Location,
+ const char* type,
+ bool *ok);
+
+ void CheckDelayedStrictModeViolation(int beg_pos, int end_pos, bool* ok);
+
+ void StrictModeIdentifierViolation(i::Scanner::Location,
+ const char* eval_args_type,
+ Identifier identifier,
+ bool* ok);
+
i::JavaScriptScanner* scanner_;
i::ParserRecorder* log_;
Scope* scope_;
uintptr_t stack_limit_;
+ i::Scanner::Location strict_mode_violation_location_;
+ const char* strict_mode_violation_type_;
bool stack_overflow_;
bool allow_lazy_;
bool parenthesized_function_;
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 099977c..82696a9 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -1736,7 +1736,7 @@
switch (object->map()->instance_type()) {
case MAP_TYPE: return "system / Map";
case JS_GLOBAL_PROPERTY_CELL_TYPE: return "system / JSGlobalPropertyCell";
- case PROXY_TYPE: return "system / Proxy";
+ case FOREIGN_TYPE: return "system / Foreign";
case ODDBALL_TYPE: return "system / Oddball";
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: return "system / "#Name;
diff --git a/src/property.h b/src/property.h
index ad80677..87f9ea3 100644
--- a/src/property.h
+++ b/src/property.h
@@ -157,10 +157,10 @@
class CallbacksDescriptor: public Descriptor {
public:
CallbacksDescriptor(String* key,
- Object* proxy,
+ Object* foreign,
PropertyAttributes attributes,
int index = 0)
- : Descriptor(key, proxy, attributes, CALLBACKS, index) {}
+ : Descriptor(key, foreign, attributes, CALLBACKS, index) {}
};
diff --git a/src/proxy.js b/src/proxy.js
index 01d48b4..c11852b 100644
--- a/src/proxy.js
+++ b/src/proxy.js
@@ -63,3 +63,21 @@
if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
return %CreateJSProxy(handler, proto)
}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtins
+////////////////////////////////////////////////////////////////////////////////
+
+function DerivedGetTrap(receiver, name) {
+ var desc = this.getPropertyDescriptor(name)
+ if (IS_UNDEFINED(desc)) { return desc; }
+ if ('value' in desc) {
+ return desc.value
+ } else {
+ if (IS_UNDEFINED(desc.get)) { return desc.get; }
+ return desc.get.call(receiver) // The proposal says so...
+ }
+}
diff --git a/src/runtime.cc b/src/runtime.cc
index 7b90469..92fa840 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -603,6 +603,7 @@
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, key, args[0]);
Object* value = args[1];
+ ASSERT(!value->IsFailure());
// Create a catch context extension object.
JSFunction* constructor =
isolate->context()->global_context()->
@@ -9356,7 +9357,7 @@
return result->GetConstantFunction();
case CALLBACKS: {
Object* structure = result->GetCallbackObject();
- if (structure->IsProxy() || structure->IsAccessorInfo()) {
+ if (structure->IsForeign() || structure->IsAccessorInfo()) {
MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
receiver, structure, name, result->holder());
if (!maybe_value->ToObject(&value)) {
diff --git a/src/runtime.js b/src/runtime.js
index 66e1661..77b97ae 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -647,20 +647,3 @@
// that is cloned when running the code. It is essential that the
// boilerplate gets the right prototype.
%FunctionSetPrototype($Array, new $Array(0));
-
-
-/* ------------------------------------------
-- - - H a r m o n y P r o x i e s - - -
----------------------------------------------
-*/
-
-function DERIVED_GET_TRAP(receiver, name) {
- var desc = this.getPropertyDescriptor(name);
- if (IS_UNDEFINED(desc)) { return desc; }
- if ('value' in desc) {
- return desc.value;
- } else {
- if (IS_UNDEFINED(desc.get)) { return desc.get; }
- return desc.get().call(receiver); // The proposal says so...
- }
-}
diff --git a/src/spaces.cc b/src/spaces.cc
index 3d3e048..cda498d 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-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:
@@ -1564,10 +1564,8 @@
CASE(BUILTIN);
CASE(LOAD_IC);
CASE(KEYED_LOAD_IC);
- CASE(KEYED_EXTERNAL_ARRAY_LOAD_IC);
CASE(STORE_IC);
CASE(KEYED_STORE_IC);
- CASE(KEYED_EXTERNAL_ARRAY_STORE_IC);
CASE(CALL_IC);
CASE(KEYED_CALL_IC);
CASE(TYPE_RECORDING_UNARY_OP_IC);
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 7a1b185..0d36856 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-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:
@@ -457,34 +457,6 @@
}
-MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
- // Using NORMAL as the PropertyType for array element loads is a misuse. The
- // generated stub always accesses fast elements, not slow-mode fields, but
- // some property type is required for the stub lookup. Note that overloading
- // the NORMAL PropertyType is only safe as long as no stubs are generated for
- // other keyed field loads. This is guaranteed to be the case since all field
- // keyed loads that are not array elements go through a generic builtin stub.
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
- String* name = heap()->KeyedLoadSpecialized_symbol();
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
- return code;
-}
-
-
MaybeObject* StubCache::ComputeStoreField(String* name,
JSObject* receiver,
int field_index,
@@ -513,30 +485,6 @@
}
-MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
- JSObject* receiver,
- StrictModeFlag strict_mode) {
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
- String* name = heap()->KeyedStoreSpecialized_symbol();
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedStoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
- return code;
-}
-
-
namespace {
ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
@@ -565,60 +513,6 @@
}
}
-String* ExternalArrayTypeToStubName(Heap* heap,
- ExternalArrayType array_type,
- bool is_store) {
- if (is_store) {
- switch (array_type) {
- case kExternalByteArray:
- return heap->KeyedStoreExternalByteArray_symbol();
- case kExternalUnsignedByteArray:
- return heap->KeyedStoreExternalUnsignedByteArray_symbol();
- case kExternalShortArray:
- return heap->KeyedStoreExternalShortArray_symbol();
- case kExternalUnsignedShortArray:
- return heap->KeyedStoreExternalUnsignedShortArray_symbol();
- case kExternalIntArray:
- return heap->KeyedStoreExternalIntArray_symbol();
- case kExternalUnsignedIntArray:
- return heap->KeyedStoreExternalUnsignedIntArray_symbol();
- case kExternalFloatArray:
- return heap->KeyedStoreExternalFloatArray_symbol();
- case kExternalDoubleArray:
- return heap->KeyedStoreExternalDoubleArray_symbol();
- case kExternalPixelArray:
- return heap->KeyedStoreExternalPixelArray_symbol();
- default:
- UNREACHABLE();
- return NULL;
- }
- } else {
- switch (array_type) {
- case kExternalByteArray:
- return heap->KeyedLoadExternalByteArray_symbol();
- case kExternalUnsignedByteArray:
- return heap->KeyedLoadExternalUnsignedByteArray_symbol();
- case kExternalShortArray:
- return heap->KeyedLoadExternalShortArray_symbol();
- case kExternalUnsignedShortArray:
- return heap->KeyedLoadExternalUnsignedShortArray_symbol();
- case kExternalIntArray:
- return heap->KeyedLoadExternalIntArray_symbol();
- case kExternalUnsignedIntArray:
- return heap->KeyedLoadExternalUnsignedIntArray_symbol();
- case kExternalFloatArray:
- return heap->KeyedLoadExternalFloatArray_symbol();
- case kExternalDoubleArray:
- return heap->KeyedLoadExternalDoubleArray_symbol();
- case kExternalPixelArray:
- return heap->KeyedLoadExternalPixelArray_symbol();
- default:
- UNREACHABLE();
- return NULL;
- }
- }
-}
-
} // anonymous namespace
@@ -628,37 +522,88 @@
StrictModeFlag strict_mode) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(
- is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
- Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
+ is_store ? Code::KEYED_STORE_IC :
+ Code::KEYED_LOAD_IC,
NORMAL,
strict_mode);
ExternalArrayType array_type =
ElementsKindToExternalArrayType(receiver->GetElementsKind());
- String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- ExternalArrayStubCompiler compiler;
- { MaybeObject* maybe_code =
- is_store ?
- compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
- compiler.CompileKeyedLoadStub(receiver, array_type, flags);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- Code::cast(code)->set_external_array_type(array_type);
- if (is_store) {
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
- Code::cast(code), 0));
- } else {
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
- Code::cast(code), 0));
- }
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ String* name = is_store
+ ? isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol()
+ : isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
+ Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
+ if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
+
+ MaybeObject* maybe_new_code = NULL;
+ if (is_store) {
+ ExternalArrayStoreStubCompiler compiler(strict_mode);
+ maybe_new_code = compiler.CompileStore(receiver, array_type);
+ } else {
+ ExternalArrayLoadStubCompiler compiler(strict_mode);
+ maybe_new_code = compiler.CompileLoad(receiver, array_type);
+ }
+ Code* code;
+ if (!maybe_new_code->To(&code)) return maybe_new_code;
+ code->set_external_array_type(array_type);
+ if (is_store) {
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
+ Code::cast(code), 0));
+ } else {
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
+ Code::cast(code), 0));
+ }
+ ASSERT(code->IsCode());
+ Object* result;
+ { MaybeObject* maybe_result =
+ receiver->UpdateMapCodeCache(name, Code::cast(code));
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ return code;
+}
+
+
+MaybeObject* StubCache::ComputeKeyedLoadOrStoreFastElement(
+ JSObject* receiver,
+ bool is_store,
+ StrictModeFlag strict_mode) {
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(
+ is_store ? Code::KEYED_STORE_IC :
+ Code::KEYED_LOAD_IC,
+ NORMAL,
+ strict_mode);
+ String* name = is_store
+ ? isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol()
+ : isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
+ Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
+ if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
+
+ MaybeObject* maybe_new_code = NULL;
+ if (is_store) {
+ KeyedStoreStubCompiler compiler(strict_mode);
+ maybe_new_code = compiler.CompileStoreFastElement(receiver->map());
+ } else {
+ KeyedLoadStubCompiler compiler;
+ maybe_new_code = compiler.CompileLoadFastElement(receiver->map());
+ }
+ Code* code;
+ if (!maybe_new_code->To(&code)) return maybe_new_code;
+ if (is_store) {
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
+ Code::cast(code), 0));
+ } else {
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
+ Code::cast(code), 0));
+ }
+ ASSERT(code->IsCode());
+ Object* result;
+ { MaybeObject* maybe_result =
+ receiver->UpdateMapCodeCache(name, Code::cast(code));
+ if (!maybe_result->ToObject(&result)) return maybe_result;
}
return code;
}
@@ -1717,8 +1662,11 @@
}
-MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
+MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
+ String* name,
+ InlineCacheState state) {
+ Code::Flags flags = Code::ComputeFlags(
+ Code::KEYED_LOAD_IC, NOT_IN_LOOP, state, Code::kNoExtraICState, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1750,9 +1698,11 @@
}
-MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_STORE_IC, type, strict_mode_);
+MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
+ String* name,
+ InlineCacheState state) {
+ Code::Flags flags = Code::ComputeFlags(
+ Code::KEYED_STORE_IC, NOT_IN_LOOP, state, strict_mode_, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1930,15 +1880,36 @@
}
-MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
+MaybeObject* ExternalArrayLoadStubCompiler::GetCode() {
Object* result;
- { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
+ Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
+ NORMAL,
+ strict_mode_);
+ { MaybeObject* maybe_result = GetCodeWithFlags(flags,
+ "ExternalArrayLoadStub");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Code* code = Code::cast(result);
USE(code);
PROFILE(isolate(),
- CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
+ CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayLoadStub"));
+ return result;
+}
+
+
+MaybeObject* ExternalArrayStoreStubCompiler::GetCode() {
+ Object* result;
+ Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC,
+ NORMAL,
+ strict_mode_);
+ { MaybeObject* maybe_result = GetCodeWithFlags(flags,
+ "ExternalArrayStoreStub");
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ Code* code = Code::cast(result);
+ USE(code);
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStoreStub"));
return result;
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 358f205..3a6b8e4 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 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:
@@ -31,6 +31,7 @@
#include "allocation.h"
#include "arguments.h"
#include "macro-assembler.h"
+#include "objects.h"
#include "zone-inl.h"
namespace v8 {
@@ -144,9 +145,6 @@
String* name,
JSFunction* receiver);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadSpecialized(
- JSObject* receiver);
-
// ---
MUST_USE_RESULT MaybeObject* ComputeStoreField(
@@ -185,16 +183,15 @@
Map* transition,
StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* ComputeKeyedStoreSpecialized(
- JSObject* receiver,
- StrictModeFlag strict_mode);
-
-
MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreExternalArray(
JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode);
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreFastElement(
+ JSObject* receiver,
+ bool is_store,
+ StrictModeFlag strict_mode);
// ---
MUST_USE_RESULT MaybeObject* ComputeCallField(int argc,
@@ -469,7 +466,10 @@
Register scratch,
Label* miss_label);
- static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
+ static void GenerateLoadMiss(MacroAssembler* masm,
+ Code::Kind kind);
+
+ static void GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm);
// Generates code that verifies that the property holder has not changed
// (checking maps of objects in the prototype chain for fast and global
@@ -634,10 +634,21 @@
MUST_USE_RESULT MaybeObject* CompileLoadStringLength(String* name);
MUST_USE_RESULT MaybeObject* CompileLoadFunctionPrototype(String* name);
- MUST_USE_RESULT MaybeObject* CompileLoadSpecialized(JSObject* receiver);
+ MUST_USE_RESULT MaybeObject* CompileLoadFastElement(Map* receiver_map);
+
+ MUST_USE_RESULT MaybeObject* CompileLoadMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics);
+
+ static void GenerateLoadExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type);
+
+ static void GenerateLoadFastElement(MacroAssembler* masm);
private:
- MaybeObject* GetCode(PropertyType type, String* name);
+ MaybeObject* GetCode(PropertyType type,
+ String* name,
+ InlineCacheState state = MONOMORPHIC);
};
@@ -678,10 +689,22 @@
Map* transition,
String* name);
- MUST_USE_RESULT MaybeObject* CompileStoreSpecialized(JSObject* receiver);
+ MUST_USE_RESULT MaybeObject* CompileStoreFastElement(Map* receiver_map);
+
+ MUST_USE_RESULT MaybeObject* CompileStoreMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics);
+
+ static void GenerateStoreFastElement(MacroAssembler* masm,
+ bool is_js_array);
+
+ static void GenerateStoreExternalArray(MacroAssembler* masm,
+ ExternalArrayType array_type);
private:
- MaybeObject* GetCode(PropertyType type, String* name);
+ MaybeObject* GetCode(PropertyType type,
+ String* name,
+ InlineCacheState state = MONOMORPHIC);
StrictModeFlag strict_mode_;
};
@@ -848,20 +871,36 @@
CallHandlerInfo* api_call_info_;
};
-class ExternalArrayStubCompiler: public StubCompiler {
+class ExternalArrayLoadStubCompiler: public StubCompiler {
public:
- explicit ExternalArrayStubCompiler() {}
+ explicit ExternalArrayLoadStubCompiler(StrictModeFlag strict_mode)
+ : strict_mode_(strict_mode) { }
- MUST_USE_RESULT MaybeObject* CompileKeyedLoadStub(
- JSObject* receiver, ExternalArrayType array_type, Code::Flags flags);
-
- MUST_USE_RESULT MaybeObject* CompileKeyedStoreStub(
- JSObject* receiver, ExternalArrayType array_type, Code::Flags flags);
+ MUST_USE_RESULT MaybeObject* CompileLoad(
+ JSObject* receiver, ExternalArrayType array_type);
private:
- MaybeObject* GetCode(Code::Flags flags);
+ MaybeObject* GetCode();
+
+ StrictModeFlag strict_mode_;
};
+
+class ExternalArrayStoreStubCompiler: public StubCompiler {
+ public:
+ explicit ExternalArrayStoreStubCompiler(StrictModeFlag strict_mode)
+ : strict_mode_(strict_mode) {}
+
+ MUST_USE_RESULT MaybeObject* CompileStore(
+ JSObject* receiver, ExternalArrayType array_type);
+
+ private:
+ MaybeObject* GetCode();
+
+ StrictModeFlag strict_mode_;
+};
+
+
} } // namespace v8::internal
#endif // V8_STUB_CACHE_H_
diff --git a/src/type-info.cc b/src/type-info.cc
index 346f8cb..3d8d4b5 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -81,8 +81,9 @@
Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
- Handle<Code> code(Code::cast(*map_or_code));
- return code->kind() == Code::KEYED_EXTERNAL_ARRAY_LOAD_IC &&
+ Handle<Code> code = Handle<Code>::cast(map_or_code);
+ return code->is_keyed_load_stub() &&
+ code->ic_state() == MONOMORPHIC &&
code->FindFirstMap() != NULL;
}
return false;
@@ -93,9 +94,9 @@
Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
- Handle<Code> code(Code::cast(*map_or_code));
- return code->kind() == Code::KEYED_EXTERNAL_ARRAY_STORE_IC &&
- code->FindFirstMap() != NULL;
+ Handle<Code> code = Handle<Code>::cast(map_or_code);
+ return code->is_keyed_store_stub() &&
+ code->ic_state() == MONOMORPHIC;
}
return false;
}
@@ -109,25 +110,25 @@
Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
ASSERT(LoadIsMonomorphic(expr));
- Handle<Object> map_or_code(
- Handle<HeapObject>::cast(GetInfo(expr->id())));
+ Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsCode()) {
- Handle<Code> code(Code::cast(*map_or_code));
- return Handle<Map>(code->FindFirstMap());
+ Handle<Code> code = Handle<Code>::cast(map_or_code);
+ Map* first_map = code->FindFirstMap();
+ ASSERT(first_map != NULL);
+ return Handle<Map>(first_map);
}
- return Handle<Map>(Map::cast(*map_or_code));
+ return Handle<Map>::cast(map_or_code);
}
Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) {
ASSERT(StoreIsMonomorphic(expr));
- Handle<HeapObject> map_or_code(
- Handle<HeapObject>::cast(GetInfo(expr->id())));
+ Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsCode()) {
- Handle<Code> code(Code::cast(*map_or_code));
+ Handle<Code> code = Handle<Code>::cast(map_or_code);
return Handle<Map>(code->FindFirstMap());
}
- return Handle<Map>(Map::cast(*map_or_code));
+ return Handle<Map>::cast(map_or_code);
}
@@ -445,8 +446,8 @@
kind == Code::COMPARE_IC) {
SetInfo(id, target);
} else if (state == MONOMORPHIC) {
- if (kind == Code::KEYED_EXTERNAL_ARRAY_LOAD_IC ||
- kind == Code::KEYED_EXTERNAL_ARRAY_STORE_IC) {
+ if (kind == Code::KEYED_LOAD_IC ||
+ kind == Code::KEYED_STORE_IC) {
SetInfo(id, target);
} else if (kind != Code::CALL_IC ||
target->check_type() == RECEIVER_MAP_CHECK) {
diff --git a/src/v8-counters.h b/src/v8-counters.h
index 5e765b2..e3b16e9 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -1,4 +1,4 @@
-// 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:
@@ -134,6 +134,7 @@
SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \
SC(keyed_load_generic_lookup_cache, V8.KeyedLoadGenericLookupCache) \
SC(keyed_load_generic_slow, V8.KeyedLoadGenericSlow) \
+ SC(keyed_load_polymorphic_stubs, V8.KeyedLoadPolymorphicStubs) \
SC(keyed_load_external_array_slow, V8.KeyedLoadExternalArraySlow) \
/* How is the generic keyed-call stub used? */ \
SC(keyed_call_generic_smi_fast, V8.KeyedCallGenericSmiFast) \
@@ -179,6 +180,8 @@
SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \
SC(named_store_global_inline, V8.NamedStoreGlobalInline) \
SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \
+ SC(keyed_store_polymorphic_stubs, V8.KeyedStorePolymorphicStubs) \
+ SC(keyed_store_external_array_slow, V8.KeyedStoreExternalArraySlow) \
SC(store_normal_miss, V8.StoreNormalMiss) \
SC(store_normal_hit, V8.StoreNormalHit) \
SC(cow_arrays_created_stub, V8.COWArraysCreatedStub) \
diff --git a/src/v8globals.h b/src/v8globals.h
index 1f34d97..ef9d707 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -154,7 +154,7 @@
class MaybeObject;
class OldSpace;
class Property;
-class Proxy;
+class Foreign;
class RegExpNode;
struct RegExpCompileData;
class RegExpTree;
diff --git a/src/v8natives.js b/src/v8natives.js
index 8db736c..d22e94d 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -148,17 +148,6 @@
}
-// execScript for IE compatibility.
-function GlobalExecScript(expr, lang) {
- // NOTE: We don't care about the character casing.
- if (!lang || /javascript/i.test(lang)) {
- var f = %CompileString(ToString(expr));
- %_CallFunction(%GlobalReceiver(global), f);
- }
- return null;
-}
-
-
// ----------------------------------------------------------------------------
@@ -178,8 +167,7 @@
"isFinite", GlobalIsFinite,
"parseInt", GlobalParseInt,
"parseFloat", GlobalParseFloat,
- "eval", GlobalEval,
- "execScript", GlobalExecScript
+ "eval", GlobalEval
));
}
diff --git a/src/version.cc b/src/version.cc
index 95567c9..47e8621 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 3
-#define BUILD_NUMBER 8
-#define PATCH_LEVEL 1
+#define BUILD_NUMBER 9
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 702d06a..a53505d 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -235,6 +235,22 @@
Label false_result, true_result, not_string;
__ movq(rax, Operand(rsp, 1 * kPointerSize));
+ // undefined -> false
+ __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ j(equal, &false_result);
+
+ // Boolean -> its value
+ __ CompareRoot(rax, Heap::kFalseValueRootIndex);
+ __ j(equal, &false_result);
+ __ CompareRoot(rax, Heap::kTrueValueRootIndex);
+ __ j(equal, &true_result);
+
+ // Smis: 0 -> false, all other -> true
+ __ Cmp(rax, Smi::FromInt(0));
+ __ j(equal, &false_result);
+ Condition is_smi = __ CheckSmi(rax);
+ __ j(is_smi, &true_result);
+
// 'null' => false.
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ j(equal, &false_result, Label::kNear);
@@ -508,12 +524,14 @@
void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow, Label::kNear);
+ Label non_smi, slow, call_builtin;
+ GenerateSmiCodeSub(masm, &non_smi, &call_builtin, Label::kNear);
__ bind(&non_smi);
GenerateHeapNumberCodeSub(masm, &slow);
__ bind(&slow);
GenerateTypeTransition(masm);
+ __ bind(&call_builtin);
+ GenerateGenericCodeFallback(masm);
}
@@ -994,7 +1012,7 @@
// We need tagged values in rdx and rax for the following code,
// not int32 in rax and rcx.
__ Integer32ToSmi(rax, rcx);
- __ Integer32ToSmi(rdx, rax);
+ __ Integer32ToSmi(rdx, rbx);
__ jmp(allocation_failure);
}
break;
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 3194e8a..d5a220f 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -553,25 +553,10 @@
void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
- // Emit the inlined tests assumed by the stub.
- __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
- __ j(equal, if_false);
- __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
- __ j(equal, if_true);
- __ CompareRoot(result_register(), Heap::kFalseValueRootIndex);
- __ j(equal, if_false);
- STATIC_ASSERT(kSmiTag == 0);
- __ Cmp(result_register(), Smi::FromInt(0));
- __ j(equal, if_false);
- Condition is_smi = masm_->CheckSmi(result_register());
- __ j(is_smi, if_true);
-
- // Call the ToBoolean stub for all other cases.
ToBooleanStub stub;
__ push(result_register());
__ CallStub(&stub);
__ testq(rax, rax);
-
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
}
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 4ba1978..f05e6a2 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -658,7 +658,7 @@
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
@@ -701,7 +701,7 @@
1);
__ bind(&slow);
- GenerateMiss(masm);
+ GenerateMiss(masm, false);
}
@@ -1240,7 +1240,7 @@
}
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -1256,8 +1256,10 @@
__ push(rbx); // return address
// Perform tail call to the entry.
- ExternalReference ref
- = ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
+ ExternalReference ref = force_generic
+ ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
+ masm->isolate())
+ : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1441,7 +1443,7 @@
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -1456,8 +1458,30 @@
__ push(rbx); // return address
// Do tail-call to runtime routine.
- ExternalReference ref =
- ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
+ ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
+ __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+
+ __ pop(rbx);
+ __ push(rdx); // receiver
+ __ push(rcx); // key
+ __ push(rax); // value
+ __ push(rbx); // return address
+
+ // Do tail-call to runtime routine.
+ ExternalReference ref = force_generic
+ ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
+ masm->isolate())
+ : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index bfffc9c..580d53b 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1046,108 +1046,94 @@
LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HValue* v = instr->value();
- if (v->EmitAtUses()) {
- if (v->IsClassOfTest()) {
- HClassOfTest* compare = HClassOfTest::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
- TempRegister());
- } else if (v->IsCompare()) {
- HCompare* compare = HCompare::cast(v);
- Token::Value op = compare->token();
- HValue* left = compare->left();
- HValue* right = compare->right();
- Representation r = compare->GetInputRepresentation();
- if (r.IsInteger32()) {
- ASSERT(left->representation().IsInteger32());
- ASSERT(right->representation().IsInteger32());
-
- return new LCmpIDAndBranch(UseRegisterAtStart(left),
- UseOrConstantAtStart(right));
- } else if (r.IsDouble()) {
- ASSERT(left->representation().IsDouble());
- ASSERT(right->representation().IsDouble());
-
- return new LCmpIDAndBranch(UseRegisterAtStart(left),
- UseRegisterAtStart(right));
- } else {
- ASSERT(left->representation().IsTagged());
- ASSERT(right->representation().IsTagged());
- bool reversed = op == Token::GT || op == Token::LTE;
- LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
- LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
- LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
- right_operand);
- return MarkAsCall(result, instr);
- }
- } else if (v->IsIsSmi()) {
- HIsSmi* compare = HIsSmi::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsSmiAndBranch(Use(compare->value()));
- } else if (v->IsIsUndetectable()) {
- HIsUndetectable* compare = HIsUndetectable::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
- TempRegister());
- } else if (v->IsHasInstanceType()) {
- HHasInstanceType* compare = HHasInstanceType::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LHasInstanceTypeAndBranch(
- UseRegisterAtStart(compare->value()));
- } else if (v->IsHasCachedArrayIndex()) {
- HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- return new LHasCachedArrayIndexAndBranch(
- UseRegisterAtStart(compare->value()));
- } else if (v->IsIsNull()) {
- HIsNull* compare = HIsNull::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
-
- // We only need a temp register for non-strict compare.
- LOperand* temp = compare->is_strict() ? NULL : TempRegister();
- return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
- temp);
- } else if (v->IsIsObject()) {
- HIsObject* compare = HIsObject::cast(v);
- ASSERT(compare->value()->representation().IsTagged());
- return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
- } else if (v->IsCompareJSObjectEq()) {
- HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
- return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
- UseRegisterAtStart(compare->right()));
- } else if (v->IsCompareSymbolEq()) {
- HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
- return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
- UseRegisterAtStart(compare->right()));
- } else if (v->IsInstanceOf()) {
- HInstanceOf* instance_of = HInstanceOf::cast(v);
- LInstanceOfAndBranch* result =
- new LInstanceOfAndBranch(UseFixed(instance_of->left(), rax),
- UseFixed(instance_of->right(), rdx));
- return MarkAsCall(result, instr);
- } else if (v->IsTypeofIs()) {
- HTypeofIs* typeof_is = HTypeofIs::cast(v);
- return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
- } else if (v->IsIsConstructCall()) {
- return new LIsConstructCallAndBranch(TempRegister());
+ if (!v->EmitAtUses()) {
+ return new LBranch(UseRegisterAtStart(v));
+ } else if (v->IsClassOfTest()) {
+ HClassOfTest* compare = HClassOfTest::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
+ TempRegister());
+ } else if (v->IsCompare()) {
+ HCompare* compare = HCompare::cast(v);
+ Token::Value op = compare->token();
+ HValue* left = compare->left();
+ HValue* right = compare->right();
+ Representation r = compare->GetInputRepresentation();
+ if (r.IsInteger32()) {
+ ASSERT(left->representation().IsInteger32());
+ ASSERT(right->representation().IsInteger32());
+ return new LCmpIDAndBranch(UseRegisterAtStart(left),
+ UseOrConstantAtStart(right));
+ } else if (r.IsDouble()) {
+ ASSERT(left->representation().IsDouble());
+ ASSERT(right->representation().IsDouble());
+ return new LCmpIDAndBranch(UseRegisterAtStart(left),
+ UseRegisterAtStart(right));
} else {
- if (v->IsConstant()) {
- if (HConstant::cast(v)->ToBoolean()) {
- return new LGoto(instr->FirstSuccessor()->block_id());
- } else {
- return new LGoto(instr->SecondSuccessor()->block_id());
- }
- }
- Abort("Undefined compare before branch");
- return NULL;
+ ASSERT(left->representation().IsTagged());
+ ASSERT(right->representation().IsTagged());
+ bool reversed = op == Token::GT || op == Token::LTE;
+ LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
+ LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
+ LCmpTAndBranch* result = new LCmpTAndBranch(left_operand, right_operand);
+ return MarkAsCall(result, instr);
}
+ } else if (v->IsIsSmi()) {
+ HIsSmi* compare = HIsSmi::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsSmiAndBranch(Use(compare->value()));
+ } else if (v->IsIsUndetectable()) {
+ HIsUndetectable* compare = HIsUndetectable::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
+ TempRegister());
+ } else if (v->IsHasInstanceType()) {
+ HHasInstanceType* compare = HHasInstanceType::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()));
+ } else if (v->IsHasCachedArrayIndex()) {
+ HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LHasCachedArrayIndexAndBranch(
+ UseRegisterAtStart(compare->value()));
+ } else if (v->IsIsNull()) {
+ HIsNull* compare = HIsNull::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ // We only need a temp register for non-strict compare.
+ LOperand* temp = compare->is_strict() ? NULL : TempRegister();
+ return new LIsNullAndBranch(UseRegisterAtStart(compare->value()), temp);
+ } else if (v->IsIsObject()) {
+ HIsObject* compare = HIsObject::cast(v);
+ ASSERT(compare->value()->representation().IsTagged());
+ return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
+ } else if (v->IsCompareJSObjectEq()) {
+ HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
+ return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
+ UseRegisterAtStart(compare->right()));
+ } else if (v->IsCompareSymbolEq()) {
+ HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
+ return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
+ UseRegisterAtStart(compare->right()));
+ } else if (v->IsInstanceOf()) {
+ HInstanceOf* instance_of = HInstanceOf::cast(v);
+ LInstanceOfAndBranch* result =
+ new LInstanceOfAndBranch(UseFixed(instance_of->left(), rax),
+ UseFixed(instance_of->right(), rdx));
+ return MarkAsCall(result, instr);
+ } else if (v->IsTypeofIs()) {
+ HTypeofIs* typeof_is = HTypeofIs::cast(v);
+ return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+ } else if (v->IsIsConstructCall()) {
+ return new LIsConstructCallAndBranch(TempRegister());
+ } else if (v->IsConstant()) {
+ HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
+ ? instr->FirstSuccessor()
+ : instr->SecondSuccessor();
+ return new LGoto(successor->block_id());
+ } else {
+ Abort("Undefined compare before branch");
+ return NULL;
}
- return new LBranch(UseRegisterAtStart(v));
}
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 185c3a5..64f42f4 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -2601,6 +2601,21 @@
}
+void MacroAssembler::DispatchMap(Register obj,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type) {
+ Label fail;
+ if (smi_check_type == DO_SMI_CHECK) {
+ JumpIfSmi(obj, &fail);
+ }
+ Cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
+ j(equal, success, RelocInfo::CODE_TARGET);
+
+ bind(&fail);
+}
+
+
void MacroAssembler::AbortIfNotNumber(Register object) {
Label ok;
Condition is_smi = CheckSmi(object);
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 0e46253..d7d5af3 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -45,6 +45,7 @@
RESULT_CONTAINS_TOP = 1 << 1
};
+
// Default scratch register used by MacroAssembler (and other code that needs
// a spare register). The register isn't callee save, and not used by the
// function calling convention.
@@ -752,6 +753,14 @@
Label* fail,
SmiCheckType smi_check_type);
+ // Check if the map of an object is equal to a specified map and branch to a
+ // specified target if equal. Skip the smi check if not required (object is
+ // known to be a heap object)
+ void DispatchMap(Register obj,
+ Handle<Map> map,
+ Handle<Code> success,
+ SmiCheckType smi_check_type);
+
// Check if the object in register heap_object is a string. Afterwards the
// register map contains the object map and the register instance_type
// contains the instance_type. The registers map and instance_type can be the
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index a3e664a..143d8d8 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -703,6 +703,14 @@
}
+void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
+ Code* code = masm->isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_MissForceGeneric);
+ Handle<Code> ic(code);
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
@@ -1954,6 +1962,7 @@
// repatch it to global receiver.
if (object->IsGlobalObject()) return heap()->undefined_value();
if (cell != NULL) return heap()->undefined_value();
+ if (!object->IsJSObject()) return heap()->undefined_value();
int depth = optimization.GetPrototypeDepthOfExpectedType(
JSObject::cast(object), holder);
if (depth == kInvalidProtoDepth) return heap()->undefined_value();
@@ -2484,8 +2493,35 @@
}
-MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
- JSObject* receiver) {
+MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement(
+ Map* receiver_map) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ MaybeObject* maybe_stub =
+ KeyedStoreFastElementStub(is_js_array).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(rdx,
+ Handle<Map>(receiver_map),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL);
+}
+
+
+MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -2493,51 +2529,26 @@
// -- rsp[0] : return address
// -----------------------------------
Label miss;
-
- // Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
- // Check that the map matches.
- __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
- Handle<Map>(receiver->map()));
- __ j(not_equal, &miss);
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &miss);
-
- // Get the elements array and make sure it is a fast element array, not 'cow'.
- __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
- __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
- factory()->fixed_array_map());
- __ j(not_equal, &miss);
-
- // Check that the key is within bounds.
- if (receiver->IsJSArray()) {
- __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
- __ j(above_equal, &miss);
- } else {
- __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
- __ j(above_equal, &miss);
+ Register map_reg = rbx;
+ __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
+ int receiver_count = receiver_maps->length();
+ for (int current = 0; current < receiver_count; ++current) {
+ // Check map and tail call if there's a match
+ Handle<Map> map(receiver_maps->at(current));
+ __ Cmp(map_reg, map);
+ __ j(equal,
+ Handle<Code>(handler_ics->at(current)),
+ RelocInfo::CODE_TARGET);
}
- // Do the store and update the write barrier. Make sure to preserve
- // the value in register eax.
- __ movq(rdx, rax);
- __ SmiToInteger32(rcx, rcx);
- __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
- rax);
- __ RecordWrite(rdi, 0, rdx, rcx);
-
- // Done.
- __ ret(0);
-
- // Handle store cache miss.
__ bind(&miss);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@@ -2551,7 +2562,7 @@
// -----------------------------------
Label miss;
- // Chech that receiver is not a smi.
+ // Check that receiver is not a smi.
__ JumpIfSmi(rax, &miss);
// Check the maps of the full prototype chain. Also check that
@@ -2942,49 +2953,56 @@
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(rdx,
+ Handle<Map>(receiver_map),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+ MapList* receiver_maps,
+ CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
Label miss;
-
- // Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
- // Check that the map matches.
- __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
- Handle<Map>(receiver->map()));
- __ j(not_equal, &miss);
+ Register map_reg = rbx;
+ __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
+ int receiver_count = receiver_maps->length();
+ for (int current = 0; current < receiver_count; ++current) {
+ // Check map and tail call if there's a match
+ Handle<Map> map(receiver_maps->at(current));
+ __ Cmp(map_reg, map);
+ __ j(equal,
+ Handle<Code>(handler_ics->at(current)),
+ RelocInfo::CODE_TARGET);
+ }
- // Check that the key is a smi.
- __ JumpIfNotSmi(rax, &miss);
-
- // Get the elements array.
- __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ AssertFastElements(rcx);
-
- // Check that the key is within bounds.
- __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
- __ j(above_equal, &miss);
-
- // Load the result and make sure it's not the hole.
- SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
- __ movq(rbx, FieldOperand(rcx,
- index.reg,
- index.scale,
- FixedArray::kHeaderSize));
- __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
- __ j(equal, &miss);
- __ movq(rax, rbx);
- __ ret(0);
-
- __ bind(&miss);
+ __ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@@ -3121,30 +3139,79 @@
}
-MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
+MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad(
+ JSObject*receiver, ExternalArrayType array_type) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- Label slow;
+ MaybeObject* maybe_stub =
+ KeyedLoadExternalArrayStub(array_type).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(rdx,
+ Handle<Map>(receiver->map()),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
- // Check that the object isn't a smi.
- __ JumpIfSmi(rdx, &slow);
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode();
+}
+
+MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
+ JSObject* receiver, ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ MaybeObject* maybe_stub =
+ KeyedStoreExternalArrayStub(array_type).TryGetCode();
+ Code* stub;
+ if (!maybe_stub->To(&stub)) return maybe_stub;
+ __ DispatchMap(rdx,
+ Handle<Map>(receiver->map()),
+ Handle<Code>(stub),
+ DO_SMI_CHECK);
+
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+
+ return GetCode();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void KeyedLoadStubCompiler::GenerateLoadExternalArray(
+ MacroAssembler* masm,
+ ExternalArrayType array_type) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label slow, miss_force_generic;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
// Check that the key is a smi.
- __ JumpIfNotSmi(rax, &slow);
-
- // Check that the map matches.
- __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
- __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ JumpIfNotSmi(rax, &miss_force_generic);
// Check that the index is in range.
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ SmiToInteger32(rcx, rax);
__ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
- __ j(above_equal, &slow);
+ __ j(above_equal, &miss_force_generic);
// rax: index (as a smi)
// rdx: receiver (JSObject)
@@ -3231,7 +3298,7 @@
// Slow case: Jump to runtime.
__ bind(&slow);
- Counters* counters = isolate()->counters();
+ Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
// ----------- S t a t e -------------
@@ -3240,44 +3307,46 @@
// -- rsp[0] : return address
// -----------------------------------
- __ pop(rbx);
- __ push(rdx); // receiver
- __ push(rax); // name
- __ push(rbx); // return address
+ Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
+ // Miss case: Jump to runtime.
+ __ bind(&miss_force_generic);
- // Return the generated code.
- return GetCode(flags);
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+ __ jmp(miss_ic, RelocInfo::CODE_TARGET);
}
-MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
+void KeyedStoreStubCompiler::GenerateStoreExternalArray(
+ MacroAssembler* masm,
+ ExternalArrayType array_type) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- Label slow;
+ Label slow, miss_force_generic;
- // Check that the object isn't a smi.
- __ JumpIfSmi(rdx, &slow);
-
- // Check that the map matches.
- __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
- __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
// Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &slow);
+ __ JumpIfNotSmi(rcx, &miss_force_generic);
// Check that the index is in range.
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ SmiToInteger32(rdi, rcx); // Untag the index.
__ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
- __ j(above_equal, &slow);
+ __ j(above_equal, &miss_force_generic);
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
@@ -3411,21 +3480,116 @@
// -- rsp[0] : return address
// -----------------------------------
- __ pop(rbx);
- __ push(rdx); // receiver
- __ push(rcx); // key
- __ push(rax); // value
- __ Push(Smi::FromInt(NONE)); // PropertyAttributes
- __ Push(Smi::FromInt(
- Code::ExtractExtraICStateFromFlags(flags) & kStrictMode));
- __ push(rbx); // return address
+ Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
+ __ jmp(ic, RelocInfo::CODE_TARGET);
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
+ // Miss case: call runtime.
+ __ bind(&miss_force_generic);
- return GetCode(flags);
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ jmp(miss_ic, RelocInfo::CODE_TARGET);
}
+
+void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss_force_generic;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(rax, &miss_force_generic);
+
+ // Get the elements array.
+ __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ AssertFastElements(rcx);
+
+ // Check that the key is within bounds.
+ __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
+ __ j(above_equal, &miss_force_generic);
+
+ // Load the result and make sure it's not the hole.
+ SmiIndex index = masm->SmiToIndex(rbx, rax, kPointerSizeLog2);
+ __ movq(rbx, FieldOperand(rcx,
+ index.reg,
+ index.scale,
+ FixedArray::kHeaderSize));
+ __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
+ __ j(equal, &miss_force_generic);
+ __ movq(rax, rbx);
+ __ ret(0);
+
+ __ bind(&miss_force_generic);
+ Code* code = masm->isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_MissForceGeneric);
+ Handle<Code> ic(code);
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
+ bool is_js_array) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss_force_generic;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(rcx, &miss_force_generic);
+
+ // Get the elements array and make sure it is a fast element array, not 'cow'.
+ __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
+ Heap::kFixedArrayMapRootIndex);
+ __ j(not_equal, &miss_force_generic);
+
+ // Check that the key is within bounds.
+ if (is_js_array) {
+ __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
+ __ j(above_equal, &miss_force_generic);
+ } else {
+ __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
+ __ j(above_equal, &miss_force_generic);
+ }
+
+ // Do the store and update the write barrier. Make sure to preserve
+ // the value in register eax.
+ __ movq(rdx, rax);
+ __ SmiToInteger32(rcx, rcx);
+ __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
+ rax);
+ __ RecordWrite(rdi, 0, rdx, rcx);
+
+ // Done.
+ __ ret(0);
+
+ // Handle store cache miss.
+ __ bind(&miss_force_generic);
+ Handle<Code> ic_force_generic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
+}
+
+
#undef __
} } // namespace v8::internal