Version 3.18.0
Enabled pretenuring of fast literals in high promotion mode.
Removed preparser library; link preparser executable against full V8.
Fixed set-up of intrinsic's 'constructor' properties. (Chromium issue 229445)
ES6 symbols: extended V8 API to support symbols (issue 2158).
Removed ARM support for VFP2.
Made __proto__ a real JavaScript accessor property. (issue 1949 and issue 2606)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14304 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/accessors.cc b/src/accessors.cc
index 57062be..0b0f9b0 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -783,64 +783,6 @@
//
-// Accessors::ObjectPrototype
-//
-
-
-static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
- Object* receiver) {
- Object* current = receiver->GetPrototype(isolate);
- while (current->IsJSObject() &&
- JSObject::cast(current)->map()->is_hidden_prototype()) {
- current = current->GetPrototype(isolate);
- }
- return current;
-}
-
-
-MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
- return GetPrototypeSkipHiddenPrototypes(Isolate::Current(), receiver);
-}
-
-
-MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver_raw,
- Object* value_raw,
- void*) {
- const bool kSkipHiddenPrototypes = true;
- // To be consistent with other Set functions, return the value.
- if (!(FLAG_harmony_observation && receiver_raw->map()->is_observed()))
- return receiver_raw->SetPrototype(value_raw, kSkipHiddenPrototypes);
-
- Isolate* isolate = receiver_raw->GetIsolate();
- HandleScope scope(isolate);
- Handle<JSObject> receiver(receiver_raw);
- Handle<Object> value(value_raw, isolate);
- Handle<Object> old_value(GetPrototypeSkipHiddenPrototypes(isolate, *receiver),
- isolate);
-
- MaybeObject* result = receiver->SetPrototype(*value, kSkipHiddenPrototypes);
- Handle<Object> hresult;
- if (!result->ToHandle(&hresult, isolate)) return result;
-
- Handle<Object> new_value(GetPrototypeSkipHiddenPrototypes(isolate, *receiver),
- isolate);
- if (!new_value->SameValue(*old_value)) {
- JSObject::EnqueueChangeRecord(receiver, "prototype",
- isolate->factory()->proto_string(),
- old_value);
- }
- return *hresult;
-}
-
-
-const AccessorDescriptor Accessors::ObjectPrototype = {
- ObjectGetPrototype,
- ObjectSetPrototype,
- 0
-};
-
-
-//
// Accessors::MakeModuleExport
//
diff --git a/src/accessors.h b/src/accessors.h
index 250f742..0740d92 100644
--- a/src/accessors.h
+++ b/src/accessors.h
@@ -56,8 +56,7 @@
V(ScriptContextData) \
V(ScriptEvalFromScript) \
V(ScriptEvalFromScriptPosition) \
- V(ScriptEvalFromFunctionName) \
- V(ObjectPrototype)
+ V(ScriptEvalFromFunctionName)
// Accessors contains all predefined proxy accessors.
@@ -111,10 +110,6 @@
static MaybeObject* ScriptGetEvalFromScript(Object* object, void*);
static MaybeObject* ScriptGetEvalFromScriptPosition(Object* object, void*);
static MaybeObject* ScriptGetEvalFromFunctionName(Object* object, void*);
- static MaybeObject* ObjectGetPrototype(Object* receiver, void*);
- static MaybeObject* ObjectSetPrototype(JSObject* receiver,
- Object* value,
- void*);
// Helper functions.
static Object* FlattenNumber(Object* value);
diff --git a/src/allocation.cc b/src/allocation.cc
index 6c7a08c..94aaad3 100644
--- a/src/allocation.cc
+++ b/src/allocation.cc
@@ -28,8 +28,8 @@
#include "allocation.h"
#include <stdlib.h> // For free, malloc.
-#include <string.h> // For memcpy.
#include "checks.h"
+#include "platform.h"
#include "utils.h"
namespace v8 {
@@ -85,7 +85,7 @@
char* StrDup(const char* str) {
int length = StrLength(str);
char* result = NewArray<char>(length + 1);
- memcpy(result, str, length);
+ OS::MemCopy(result, str, length);
result[length] = '\0';
return result;
}
@@ -95,7 +95,7 @@
int length = StrLength(str);
if (n < length) length = n;
char* result = NewArray<char>(length + 1);
- memcpy(result, str, length);
+ OS::MemCopy(result, str, length);
result[length] = '\0';
return result;
}
diff --git a/src/api.cc b/src/api.cc
index 178eeab..dddcd7d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1655,7 +1655,7 @@
ScriptData* ScriptData::PreCompile(const char* input, int length) {
i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
- return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
+ return i::PreParserApi::PreParse(&stream);
}
@@ -1664,10 +1664,10 @@
if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUtf16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
- return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
+ return i::PreParserApi::PreParse(&stream);
} else {
i::GenericStringUtf16CharacterStream stream(str, 0, str->length());
- return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
+ return i::PreParserApi::PreParse(&stream);
}
}
@@ -1686,7 +1686,8 @@
}
// Copy the data to align it.
unsigned* deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
- i::OS::MemCopy(deserialized_data, data, length);
+ i::CopyBytes(reinterpret_cast<char*>(deserialized_data),
+ data, static_cast<size_t>(length));
return new i::ScriptDataImpl(
i::Vector<unsigned>(deserialized_data, deserialized_data_length));
@@ -1852,6 +1853,34 @@
}
+int Script::GetLineNumber(int code_pos) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::GetLineNumber()", return -1);
+ LOG_API(isolate, "Script::GetLineNumber");
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (obj->IsScript()) {
+ i::Handle<i::Script> script = i::Handle<i::Script>(i::Script::cast(*obj));
+ return i::GetScriptLineNumber(script, code_pos);
+ } else {
+ return -1;
+ }
+}
+
+
+Handle<Value> Script::GetScriptName() {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::GetName()", return Handle<String>());
+ LOG_API(isolate, "Script::GetName");
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ if (obj->IsScript()) {
+ i::Object* name = i::Script::cast(*obj)->name();
+ return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
+ } else {
+ return Handle<String>();
+ }
+}
+
+
void Script::SetData(v8::Handle<String> data) {
i::Isolate* isolate = i::Isolate::Current();
ON_BAILOUT(isolate, "v8::Script::SetData()", return);
@@ -2367,6 +2396,12 @@
}
+bool Value::IsSymbol() const {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsSymbol()")) return false;
+ return Utils::OpenHandle(this)->IsSymbol();
+}
+
+
bool Value::IsArray() const {
if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsArray()")) return false;
return Utils::OpenHandle(this)->IsJSArray();
@@ -2451,6 +2486,16 @@
}
+bool Value::IsSymbolObject() const {
+ // TODO(svenpanne): these and other test functions should be written such
+ // that they do not use Isolate::Current().
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::IsSymbolObject()")) return false;
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ return obj->HasSpecificClassOf(isolate->heap()->Symbol_string());
+}
+
+
bool Value::IsNumberObject() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsNumberObject()")) return false;
@@ -2664,6 +2709,15 @@
}
+void v8::Symbol::CheckCast(v8::Value* that) {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Symbol::Cast()")) return;
+ i::Handle<i::Object> obj = Utils::OpenHandle(that);
+ ApiCheck(obj->IsSymbol(),
+ "v8::Symbol::Cast()",
+ "Could not convert to symbol");
+}
+
+
void v8::Number::CheckCast(v8::Value* that) {
if (IsDeadCheck(i::Isolate::Current(), "v8::Number::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
@@ -2711,6 +2765,16 @@
}
+void v8::SymbolObject::CheckCast(v8::Value* that) {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::SymbolObject::Cast()")) return;
+ i::Handle<i::Object> obj = Utils::OpenHandle(that);
+ ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Symbol_string()),
+ "v8::SymbolObject::Cast()",
+ "Could not convert to SymbolObject");
+}
+
+
void v8::NumberObject::CheckCast(v8::Value* that) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::NumberObject::Cast()")) return;
@@ -3079,13 +3143,13 @@
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
- if (!key_obj->IsString()) {
+ if (!key_obj->IsName()) {
EXCEPTION_PREAMBLE(isolate);
key_obj = i::Execution::ToString(key_obj, &has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
}
- i::Handle<i::String> key_string = i::Handle<i::String>::cast(key_obj);
- PropertyAttributes result = self->GetPropertyAttribute(*key_string);
+ i::Handle<i::Name> key_name = i::Handle<i::Name>::cast(key_obj);
+ PropertyAttributes result = self->GetPropertyAttribute(*key_name);
if (result == ABSENT) return static_cast<PropertyAttribute>(NONE);
return static_cast<PropertyAttribute>(result);
}
@@ -3215,7 +3279,7 @@
// Write prefix.
char* ptr = buf.start();
- memcpy(ptr, prefix, prefix_len * v8::internal::kCharSize);
+ i::OS::MemCopy(ptr, prefix, prefix_len * v8::internal::kCharSize);
ptr += prefix_len;
// Write real content.
@@ -3223,7 +3287,7 @@
ptr += str_len;
// Write postfix.
- memcpy(ptr, postfix, postfix_len * v8::internal::kCharSize);
+ i::OS::MemCopy(ptr, postfix, postfix_len * v8::internal::kCharSize);
// Copy the buffer into a heap-allocated string and return it.
Local<String> result = v8::String::New(buf.start(), buf_len);
@@ -3255,24 +3319,32 @@
}
-bool v8::Object::Delete(v8::Handle<String> key) {
+bool v8::Object::Delete(v8::Handle<Value> key) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::Delete()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- return i::JSObject::DeleteProperty(self, key_obj)->IsTrue();
+ i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+ EXCEPTION_PREAMBLE(isolate);
+ i::Handle<i::Object> obj = i::DeleteProperty(self, key_obj);
+ has_pending_exception = obj.is_null();
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
+ return obj->IsTrue();
}
-bool v8::Object::Has(v8::Handle<String> key) {
+bool v8::Object::Has(v8::Handle<Value> key) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::Has()", return false);
ENTER_V8(isolate);
- i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- return self->HasProperty(*key_obj);
+ i::Handle<i::JSReceiver> self = Utils::OpenHandle(this);
+ i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+ EXCEPTION_PREAMBLE(isolate);
+ i::Handle<i::Object> obj = i::HasProperty(self, key_obj);
+ has_pending_exception = obj.is_null();
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
+ return obj->IsTrue();
}
@@ -3352,15 +3424,16 @@
ON_BAILOUT(isolate, "v8::Object::HasRealNamedProperty()",
return false);
return Utils::OpenHandle(this)->HasRealNamedProperty(
+ isolate,
*Utils::OpenHandle(*key));
}
bool v8::Object::HasRealIndexedProperty(uint32_t index) {
- ON_BAILOUT(Utils::OpenHandle(this)->GetIsolate(),
- "v8::Object::HasRealIndexedProperty()",
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::HasRealIndexedProperty()",
return false);
- return Utils::OpenHandle(this)->HasRealElementProperty(index);
+ return Utils::OpenHandle(this)->HasRealElementProperty(isolate, index);
}
@@ -3371,6 +3444,7 @@
return false);
ENTER_V8(isolate);
return Utils::OpenHandle(this)->HasRealNamedCallbackProperty(
+ isolate,
*Utils::OpenHandle(*key));
}
@@ -4591,6 +4665,15 @@
}
+Local<Value> Symbol::Name() const {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Symbol::Name()"))
+ return Local<Value>();
+ i::Handle<i::Symbol> sym = Utils::OpenHandle(this);
+ i::Handle<i::Object> name(sym->name(), sym->GetIsolate());
+ return Utils::ToLocal(name);
+}
+
+
double Number::Value() const {
if (IsDeadCheck(i::Isolate::Current(), "v8::Number::Value()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
@@ -4861,18 +4944,14 @@
}
-Persistent<Context> v8::Context::New(
+static i::Handle<i::Context> CreateEnvironment(
+ i::Isolate* isolate,
v8::ExtensionConfiguration* extensions,
v8::Handle<ObjectTemplate> global_template,
v8::Handle<Value> global_object) {
- i::Isolate::EnsureDefaultIsolate();
- i::Isolate* isolate = i::Isolate::Current();
- EnsureInitializedForIsolate(isolate, "v8::Context::New()");
- LOG_API(isolate, "Context::New");
- ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
+ i::Handle<i::Context> env;
// Enter V8 via an ENTER_V8 scope.
- i::Handle<i::Context> env;
{
ENTER_V8(isolate);
v8::Handle<ObjectTemplate> proxy_template = global_template;
@@ -4927,10 +5006,43 @@
}
// Leave V8.
- if (env.is_null()) {
- return Persistent<Context>();
- }
- return Persistent<Context>(Utils::ToLocal(env));
+ return env;
+}
+
+
+Persistent<Context> v8::Context::New(
+ v8::ExtensionConfiguration* extensions,
+ v8::Handle<ObjectTemplate> global_template,
+ v8::Handle<Value> global_object) {
+ i::Isolate::EnsureDefaultIsolate();
+ i::Isolate* isolate = i::Isolate::Current();
+ Isolate* external_isolate = reinterpret_cast<Isolate*>(isolate);
+ EnsureInitializedForIsolate(isolate, "v8::Context::New()");
+ LOG_API(isolate, "Context::New");
+ ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
+ i::HandleScope scope(isolate);
+ i::Handle<i::Context> env =
+ CreateEnvironment(isolate, extensions, global_template, global_object);
+ if (env.is_null()) return Persistent<Context>();
+ return Persistent<Context>::New(external_isolate, Utils::ToLocal(env));
+}
+
+
+Local<Context> v8::Context::New(
+ v8::Isolate* external_isolate,
+ v8::ExtensionConfiguration* extensions,
+ v8::Handle<ObjectTemplate> global_template,
+ v8::Handle<Value> global_object) {
+ i::Isolate::EnsureDefaultIsolate();
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
+ EnsureInitializedForIsolate(isolate, "v8::Context::New()");
+ LOG_API(isolate, "Context::New");
+ ON_BAILOUT(isolate, "v8::Context::New()", return Local<Context>());
+ i::HandleScope scope(isolate);
+ i::Handle<i::Context> env =
+ CreateEnvironment(isolate, extensions, global_template, global_object);
+ if (env.is_null()) return Local<Context>();
+ return Utils::ToLocal(scope.CloseAndEscape(env));
}
@@ -5005,10 +5117,7 @@
if (IsDeadCheck(isolate, "v8::Context::GetCurrent()")) {
return Local<Context>();
}
- i::Handle<i::Object> current = isolate->native_context();
- if (current.is_null()) return Local<Context>();
- i::Handle<i::Context> context = i::Handle<i::Context>::cast(current);
- return Utils::ToLocal(context);
+ return reinterpret_cast<Isolate*>(isolate)->GetCurrentContext();
}
@@ -5429,6 +5538,29 @@
}
+Local<v8::Value> v8::SymbolObject::New(Isolate* isolate, Handle<Symbol> value) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ EnsureInitializedForIsolate(i_isolate, "v8::SymbolObject::New()");
+ LOG_API(i_isolate, "SymbolObject::New");
+ ENTER_V8(i_isolate);
+ i::Handle<i::Object> obj =
+ i_isolate->factory()->ToObject(Utils::OpenHandle(*value));
+ return Utils::ToLocal(obj);
+}
+
+
+Local<v8::Symbol> v8::SymbolObject::SymbolValue() const {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::SymbolObject::SymbolValue()"))
+ return Local<v8::Symbol>();
+ LOG_API(isolate, "SymbolObject::SymbolValue");
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
+ return Utils::ToLocal(
+ i::Handle<i::Symbol>(i::Symbol::cast(jsvalue->value())));
+}
+
+
Local<v8::Value> v8::Date::New(double time) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::Date::New()");
@@ -5610,6 +5742,30 @@
}
+Local<Symbol> v8::Symbol::New(Isolate* isolate) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
+ LOG_API(i_isolate, "Symbol::New()");
+ ENTER_V8(i_isolate);
+ i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+ return Utils::ToLocal(result);
+}
+
+
+Local<Symbol> v8::Symbol::New(Isolate* isolate, const char* data, int length) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
+ LOG_API(i_isolate, "Symbol::New(char)");
+ ENTER_V8(i_isolate);
+ if (length == -1) length = i::StrLength(data);
+ i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
+ i::Vector<const char>(data, length));
+ i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+ result->set_name(*name);
+ return Utils::ToLocal(result);
+}
+
+
Local<Number> v8::Number::New(double value) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::Number::New()");
@@ -7095,7 +7251,7 @@
v8::ImplementationUtilities::HandleScopeData* current =
isolate_->handle_scope_data();
handle_scope_data_ = *current;
- memcpy(storage, this, sizeof(*this));
+ OS::MemCopy(storage, this, sizeof(*this));
ResetAfterArchive();
current->Initialize();
@@ -7110,7 +7266,7 @@
char* HandleScopeImplementer::RestoreThread(char* storage) {
- memcpy(this, storage, sizeof(*this));
+ OS::MemCopy(this, storage, sizeof(*this));
*isolate_->handle_scope_data() = handle_scope_data_;
return storage + ArchiveSpacePerThread();
}
diff --git a/src/api.h b/src/api.h
index d73646d..0cd16f1 100644
--- a/src/api.h
+++ b/src/api.h
@@ -171,6 +171,7 @@
V(Object, JSObject) \
V(Array, JSArray) \
V(String, String) \
+ V(Symbol, Symbol) \
V(Script, Object) \
V(Function, JSFunction) \
V(Message, JSObject) \
@@ -196,6 +197,8 @@
v8::internal::Handle<v8::internal::JSFunction> obj);
static inline Local<String> ToLocal(
v8::internal::Handle<v8::internal::String> obj);
+ static inline Local<Symbol> ToLocal(
+ v8::internal::Handle<v8::internal::Symbol> obj);
static inline Local<RegExp> ToLocal(
v8::internal::Handle<v8::internal::JSRegExp> obj);
static inline Local<Object> ToLocal(
@@ -268,6 +271,7 @@
MAKE_TO_LOCAL(ToLocal, Object, Value)
MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
MAKE_TO_LOCAL(ToLocal, String, String)
+MAKE_TO_LOCAL(ToLocal, Symbol, Symbol)
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
diff --git a/src/arguments.h b/src/arguments.h
index f8fb00c..1423d56 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -115,15 +115,18 @@
#define DECLARE_RUNTIME_FUNCTION(Type, Name) \
-Type Name(Arguments args, Isolate* isolate)
+Type Name(int args_length, Object** args_object, Isolate* isolate)
+#define RUNTIME_FUNCTION(Type, Name) \
+static Type __RT_impl_##Name(Arguments args, Isolate* isolate); \
+Type Name(int args_length, Object** args_object, Isolate* isolate) { \
+ Arguments args(args_length, args_object); \
+ return __RT_impl_##Name(args, isolate); \
+} \
+static Type __RT_impl_##Name(Arguments args, Isolate* isolate)
-#define RUNTIME_FUNCTION(Type, Name) \
-Type Name(Arguments args, Isolate* isolate)
-
-
-#define RUNTIME_ARGUMENTS(isolate, args) args, isolate
-
+#define RUNTIME_ARGUMENTS(isolate, args) \
+ args.length(), args.arguments(), isolate
} } // namespace v8::internal
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h
index 123013b..0f9630b 100644
--- a/src/arm/assembler-arm-inl.h
+++ b/src/arm/assembler-arm-inl.h
@@ -48,29 +48,17 @@
int Register::NumAllocatableRegisters() {
- if (CpuFeatures::IsSupported(VFP2)) {
- return kMaxNumAllocatableRegisters;
- } else {
- return kMaxNumAllocatableRegisters - kGPRsPerNonVFP2Double;
- }
+ return kMaxNumAllocatableRegisters;
}
int DwVfpRegister::NumRegisters() {
- if (CpuFeatures::IsSupported(VFP2)) {
- return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
- } else {
- return 1;
- }
+ return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
}
int DwVfpRegister::NumAllocatableRegisters() {
- if (CpuFeatures::IsSupported(VFP2)) {
- return NumRegisters() - kNumReservedRegisters;
- } else {
- return 1;
- }
+ return NumRegisters() - kNumReservedRegisters;
}
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 1574d51..bc21b64 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -63,29 +63,21 @@
static unsigned CpuFeaturesImpliedByCompiler() {
unsigned answer = 0;
#ifdef CAN_USE_ARMV7_INSTRUCTIONS
- answer |= 1u << ARMv7;
+ if (FLAG_enable_armv7) {
+ answer |= 1u << ARMv7;
+ }
#endif // CAN_USE_ARMV7_INSTRUCTIONS
#ifdef CAN_USE_VFP3_INSTRUCTIONS
- answer |= 1u << VFP3 | 1u << VFP2 | 1u << ARMv7;
+ if (FLAG_enable_vfp3) {
+ answer |= 1u << VFP3 | 1u << ARMv7;
+ }
#endif // CAN_USE_VFP3_INSTRUCTIONS
-#ifdef CAN_USE_VFP2_INSTRUCTIONS
- answer |= 1u << VFP2;
-#endif // CAN_USE_VFP2_INSTRUCTIONS
#ifdef CAN_USE_VFP32DREGS
- answer |= 1u << VFP32DREGS;
+ if (FLAG_enable_32dregs) {
+ answer |= 1u << VFP32DREGS;
+ }
#endif // CAN_USE_VFP32DREGS
-
-#ifdef __arm__
- // If the compiler is allowed to use VFP then we can use VFP too in our code
- // generation even when generating snapshots. ARMv7 and hardware floating
- // point support implies VFPv3, see ARM DDI 0406B, page A1-6.
-#if defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__) \
- && !defined(__SOFTFP__)
- answer |= 1u << VFP3 | 1u << ARMv7 | 1u << VFP2;
-#endif // defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__)
- // && !defined(__SOFTFP__)
-#endif // _arm__
- if (answer & (1u << ARMv7)) {
+ if ((answer & (1u << ARMv7)) && FLAG_enable_unaligned_accesses) {
answer |= 1u << UNALIGNED_ACCESSES;
}
@@ -94,18 +86,13 @@
const char* DwVfpRegister::AllocationIndexToString(int index) {
- if (CpuFeatures::IsSupported(VFP2)) {
- ASSERT(index >= 0 && index < NumAllocatableRegisters());
- ASSERT(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
- kNumReservedRegisters - 1);
- if (index >= kDoubleRegZero.code())
- index += kNumReservedRegisters;
+ ASSERT(index >= 0 && index < NumAllocatableRegisters());
+ ASSERT(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
+ kNumReservedRegisters - 1);
+ if (index >= kDoubleRegZero.code())
+ index += kNumReservedRegisters;
- return VFPRegisters::Name(index, true);
- } else {
- ASSERT(index == 0);
- return "sfpd0";
- }
+ return VFPRegisters::Name(index, true);
}
@@ -124,6 +111,8 @@
if (Serializer::enabled()) {
// No probing for features if we might serialize (generate snapshot).
+ printf(" ");
+ PrintFeatures();
return;
}
@@ -133,8 +122,7 @@
if (FLAG_enable_vfp3) {
supported_ |=
static_cast<uint64_t>(1) << VFP3 |
- static_cast<uint64_t>(1) << ARMv7 |
- static_cast<uint64_t>(1) << VFP2;
+ static_cast<uint64_t>(1) << ARMv7;
}
// For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled
if (FLAG_enable_armv7) {
@@ -153,48 +141,127 @@
supported_ |= static_cast<uint64_t>(1) << VFP32DREGS;
}
+ if (FLAG_enable_unaligned_accesses) {
+ supported_ |= static_cast<uint64_t>(1) << UNALIGNED_ACCESSES;
+ }
+
#else // __arm__
// Probe for additional features not already known to be available.
- if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) {
+ if (!IsSupported(VFP3) && FLAG_enable_vfp3 && OS::ArmCpuHasFeature(VFP3)) {
// This implementation also sets the VFP flags if runtime
- // detection of VFP returns true. VFPv3 implies ARMv7 and VFP2, see ARM DDI
+ // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
// 0406B, page A1-6.
found_by_runtime_probing_only_ |=
static_cast<uint64_t>(1) << VFP3 |
- static_cast<uint64_t>(1) << ARMv7 |
- static_cast<uint64_t>(1) << VFP2;
- } else if (!IsSupported(VFP2) && OS::ArmCpuHasFeature(VFP2)) {
- found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << VFP2;
+ static_cast<uint64_t>(1) << ARMv7;
}
- if (!IsSupported(ARMv7) && OS::ArmCpuHasFeature(ARMv7)) {
+ if (!IsSupported(ARMv7) && FLAG_enable_armv7 && OS::ArmCpuHasFeature(ARMv7)) {
found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << ARMv7;
}
- if (!IsSupported(SUDIV) && OS::ArmCpuHasFeature(SUDIV)) {
+ if (!IsSupported(SUDIV) && FLAG_enable_sudiv && OS::ArmCpuHasFeature(SUDIV)) {
found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << SUDIV;
}
- if (!IsSupported(UNALIGNED_ACCESSES) && OS::ArmCpuHasFeature(ARMv7)) {
+ if (!IsSupported(UNALIGNED_ACCESSES) && FLAG_enable_unaligned_accesses
+ && OS::ArmCpuHasFeature(ARMv7)) {
found_by_runtime_probing_only_ |=
static_cast<uint64_t>(1) << UNALIGNED_ACCESSES;
}
if (OS::GetCpuImplementer() == QUALCOMM_IMPLEMENTER &&
- OS::ArmCpuHasFeature(ARMv7)) {
+ FLAG_enable_movw_movt && OS::ArmCpuHasFeature(ARMv7)) {
found_by_runtime_probing_only_ |=
static_cast<uint64_t>(1) << MOVW_MOVT_IMMEDIATE_LOADS;
}
- if (!IsSupported(VFP32DREGS) && OS::ArmCpuHasFeature(VFP32DREGS)) {
+ if (!IsSupported(VFP32DREGS) && FLAG_enable_32dregs
+ && OS::ArmCpuHasFeature(VFP32DREGS)) {
found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << VFP32DREGS;
}
supported_ |= found_by_runtime_probing_only_;
#endif
- // Assert that VFP3 implies VFP2 and ARMv7.
- ASSERT(!IsSupported(VFP3) || (IsSupported(VFP2) && IsSupported(ARMv7)));
+ // Assert that VFP3 implies ARMv7.
+ ASSERT(!IsSupported(VFP3) || IsSupported(ARMv7));
+}
+
+
+void CpuFeatures::PrintTarget() {
+ const char* arm_arch = NULL;
+ const char* arm_test = "";
+ const char* arm_fpu = "";
+ const char* arm_thumb = "";
+ const char* arm_float_abi = NULL;
+
+#if defined CAN_USE_ARMV7_INSTRUCTIONS
+ arm_arch = "arm v7";
+#else
+ arm_arch = "arm v6";
+#endif
+
+#ifdef __arm__
+
+# ifdef ARM_TEST
+ arm_test = " test";
+# endif
+# if defined __ARM_NEON__
+ arm_fpu = " neon";
+# elif defined CAN_USE_VFP3_INSTRUCTIONS
+ arm_fpu = " vfp3";
+# else
+ arm_fpu = " vfp2";
+# endif
+# if (defined __thumb__) || (defined __thumb2__)
+ arm_thumb = " thumb";
+# endif
+ arm_float_abi = OS::ArmUsingHardFloat() ? "hard" : "softfp";
+
+#else // __arm__
+
+ arm_test = " simulator";
+# if defined CAN_USE_VFP3_INSTRUCTIONS
+# if defined CAN_USE_VFP32DREGS
+ arm_fpu = " vfp3";
+# else
+ arm_fpu = " vfp3-d16";
+# endif
+# else
+ arm_fpu = " vfp2";
+# endif
+# if USE_EABI_HARDFLOAT == 1
+ arm_float_abi = "hard";
+# else
+ arm_float_abi = "softfp";
+# endif
+
+#endif // __arm__
+
+ printf("target%s %s%s%s %s\n",
+ arm_test, arm_arch, arm_fpu, arm_thumb, arm_float_abi);
+}
+
+
+void CpuFeatures::PrintFeatures() {
+ printf(
+ "ARMv7=%d VFP3=%d VFP32DREGS=%d SUDIV=%d UNALIGNED_ACCESSES=%d "
+ "MOVW_MOVT_IMMEDIATE_LOADS=%d",
+ CpuFeatures::IsSupported(ARMv7),
+ CpuFeatures::IsSupported(VFP3),
+ CpuFeatures::IsSupported(VFP32DREGS),
+ CpuFeatures::IsSupported(SUDIV),
+ CpuFeatures::IsSupported(UNALIGNED_ACCESSES),
+ CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS));
+#ifdef __arm__
+ bool eabi_hardfloat = OS::ArmUsingHardFloat();
+#elif USE_EABI_HARDFLOAT
+ bool eabi_hardfloat = true;
+#else
+ bool eabi_hardfloat = false;
+#endif
+ printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat);
}
@@ -1763,7 +1830,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-924.
// cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
// Vd(15-12) | 1011(11-8) | offset
- ASSERT(IsEnabled(VFP2));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1807,7 +1873,6 @@
// Instruction details available in ARM DDI 0406A, A8-628.
// cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
// Vdst(15-12) | 1010(11-8) | offset
- ASSERT(IsEnabled(VFP2));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1851,7 +1916,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-1082.
// cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
// Vd(15-12) | 1011(11-8) | (offset/4)
- ASSERT(IsEnabled(VFP2));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1895,7 +1959,6 @@
// Instruction details available in ARM DDI 0406A, A8-786.
// cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
// Vdst(15-12) | 1010(11-8) | (offset/4)
- ASSERT(IsEnabled(VFP2));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1938,7 +2001,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-922.
// cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
// first(15-12) | 1011(11-8) | (count * 2)
- ASSERT(IsEnabled(VFP2));
ASSERT_LE(first.code(), last.code());
ASSERT(am == ia || am == ia_w || am == db_w);
ASSERT(!base.is(pc));
@@ -1960,7 +2022,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-1080.
// cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
// first(15-12) | 1011(11-8) | (count * 2)
- ASSERT(IsEnabled(VFP2));
ASSERT_LE(first.code(), last.code());
ASSERT(am == ia || am == ia_w || am == db_w);
ASSERT(!base.is(pc));
@@ -1981,7 +2042,6 @@
// Instruction details available in ARM DDI 0406A, A8-626.
// cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
// first(15-12) | 1010(11-8) | (count/2)
- ASSERT(IsEnabled(VFP2));
ASSERT_LE(first.code(), last.code());
ASSERT(am == ia || am == ia_w || am == db_w);
ASSERT(!base.is(pc));
@@ -2002,7 +2062,6 @@
// Instruction details available in ARM DDI 0406A, A8-784.
// cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
// first(15-12) | 1011(11-8) | (count/2)
- ASSERT(IsEnabled(VFP2));
ASSERT_LE(first.code(), last.code());
ASSERT(am == ia || am == ia_w || am == db_w);
ASSERT(!base.is(pc));
@@ -2016,7 +2075,7 @@
static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
uint64_t i;
- memcpy(&i, &d, 8);
+ OS::MemCopy(&i, &d, 8);
*lo = i & 0xffffffff;
*hi = i >> 32;
@@ -2076,8 +2135,6 @@
void Assembler::vmov(const DwVfpRegister dst,
double imm,
const Register scratch) {
- ASSERT(IsEnabled(VFP2));
-
uint32_t enc;
if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) {
// The double can be encoded in the instruction.
@@ -2148,7 +2205,6 @@
const Condition cond) {
// Sd = Sm
// Instruction details available in ARM DDI 0406B, A8-642.
- ASSERT(IsEnabled(VFP2));
int sd, d, sm, m;
dst.split_code(&sd, &d);
src.split_code(&sm, &m);
@@ -2163,7 +2219,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-938.
// cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
// 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vm, m;
@@ -2181,7 +2236,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-940.
// cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
// Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
- ASSERT(IsEnabled(VFP2));
ASSERT(index.index == 0 || index.index == 1);
int vd, d;
dst.split_code(&vd, &d);
@@ -2198,7 +2252,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-948.
// cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
// Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
- ASSERT(IsEnabled(VFP2));
ASSERT(!src1.is(pc) && !src2.is(pc));
int vm, m;
dst.split_code(&vm, &m);
@@ -2215,7 +2268,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-948.
// cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
// Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
- ASSERT(IsEnabled(VFP2));
ASSERT(!dst1.is(pc) && !dst2.is(pc));
int vm, m;
src.split_code(&vm, &m);
@@ -2231,7 +2283,6 @@
// Instruction details available in ARM DDI 0406A, A8-642.
// cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
// Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
- ASSERT(IsEnabled(VFP2));
ASSERT(!src.is(pc));
int sn, n;
dst.split_code(&sn, &n);
@@ -2246,7 +2297,6 @@
// Instruction details available in ARM DDI 0406A, A8-642.
// cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
// Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
- ASSERT(IsEnabled(VFP2));
ASSERT(!dst.is(pc));
int sn, n;
src.split_code(&sn, &n);
@@ -2371,7 +2421,6 @@
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
}
@@ -2380,7 +2429,6 @@
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
}
@@ -2389,7 +2437,6 @@
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
}
@@ -2398,7 +2445,6 @@
const DwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
}
@@ -2407,7 +2453,6 @@
const DwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
}
@@ -2416,7 +2461,6 @@
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
}
@@ -2425,7 +2469,6 @@
const DwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(IsEnabled(VFP2));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
}
@@ -2436,7 +2479,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-968.
// cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
// 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vm, m;
@@ -2453,7 +2495,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-524.
// cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
// 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vm, m;
@@ -2472,7 +2513,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-830.
// cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vn, n;
@@ -2493,7 +2533,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-1086.
// cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vn, n;
@@ -2514,7 +2553,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-960.
// cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vn, n;
@@ -2571,7 +2609,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-882.
// cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vn, n;
@@ -2590,7 +2627,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-864.
// cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
src1.split_code(&vd, &d);
int vm, m;
@@ -2607,7 +2643,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-864.
// cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
- ASSERT(IsEnabled(VFP2));
ASSERT(src2 == 0.0);
int vd, d;
src1.split_code(&vd, &d);
@@ -2619,7 +2654,6 @@
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
- ASSERT(IsEnabled(VFP2));
emit(cond | 0xE*B24 | 0xE*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
@@ -2629,7 +2663,6 @@
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
- ASSERT(IsEnabled(VFP2));
emit(cond | 0xE*B24 | 0xF*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
@@ -2641,7 +2674,6 @@
// Instruction details available in ARM DDI 0406C.b, A8-1058.
// cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
// Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
- ASSERT(IsEnabled(VFP2));
int vd, d;
dst.split_code(&vd, &d);
int vm, m;
@@ -2747,9 +2779,9 @@
// Copy the data.
int pc_delta = desc.buffer - buffer_;
int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
- memmove(desc.buffer, buffer_, desc.instr_size);
- memmove(reloc_info_writer.pos() + rc_delta,
- reloc_info_writer.pos(), desc.reloc_size);
+ OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+ OS::MemMove(reloc_info_writer.pos() + rc_delta,
+ reloc_info_writer.pos(), desc.reloc_size);
// Switch buffers.
DeleteArray(buffer_);
@@ -2998,7 +3030,7 @@
const double double_data = rinfo.data64();
uint64_t uint_data = 0;
- memcpy(&uint_data, &double_data, sizeof(double_data));
+ OS::MemCopy(&uint_data, &double_data, sizeof(double_data));
emit(uint_data & 0xFFFFFFFF);
emit(uint_data >> 32);
}
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 045638e..0aecbcd 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -55,16 +55,15 @@
// is enabled (snapshots must be portable).
static void Probe();
+ // Display target use when compiling.
+ static void PrintTarget();
+
+ // Display features.
+ static void PrintFeatures();
+
// Check whether a feature is supported by the target CPU.
static bool IsSupported(CpuFeature f) {
ASSERT(initialized_);
- if (f == VFP3 && !FLAG_enable_vfp3) return false;
- if (f == VFP2 && !FLAG_enable_vfp2) return false;
- if (f == SUDIV && !FLAG_enable_sudiv) return false;
- if (f == UNALIGNED_ACCESSES && !FLAG_enable_unaligned_accesses) {
- return false;
- }
- if (f == VFP32DREGS && !FLAG_enable_32dregs) return false;
return (supported_ & (1u << f)) != 0;
}
@@ -117,7 +116,6 @@
static const int kNumRegisters = 16;
static const int kMaxNumAllocatableRegisters = 8;
static const int kSizeInBytes = 4;
- static const int kGPRsPerNonVFP2Double = 2;
inline static int NumAllocatableRegisters();
@@ -214,6 +212,7 @@
// Single word VFP register.
struct SwVfpRegister {
+ static const int kSizeInBytes = 4;
bool is_valid() const { return 0 <= code_ && code_ < 32; }
bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
int code() const {
@@ -244,6 +243,7 @@
static const int kNumReservedRegisters = 2;
static const int kMaxNumAllocatableRegisters = kMaxNumRegisters -
kNumReservedRegisters;
+ static const int kSizeInBytes = 8;
// Note: the number of registers can be different at snapshot and run-time.
// Any code included in the snapshot must be able to run both with 16 or 32
@@ -370,9 +370,6 @@
const DwVfpRegister d30 = { 30 };
const DwVfpRegister d31 = { 31 };
-const Register sfpd_lo = { kRegister_r6_Code };
-const Register sfpd_hi = { kRegister_r7_Code };
-
// Aliases for double registers. Defined using #define instead of
// "static const DwVfpRegister&" because Clang complains otherwise when a
// compilation unit that includes this header doesn't use the variables.
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index d982f27..1db4152 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_ARM)
#include "bootstrapper.h"
+#include "builtins-decls.h"
#include "code-stubs.h"
#include "regexp-macro-assembler.h"
#include "stub-cache.h"
@@ -38,6 +39,18 @@
namespace internal {
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r3, r2, r1 };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->stack_parameter_count_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -133,7 +146,6 @@
Label* lhs_not_nan,
Label* slow,
bool strict);
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond);
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
Register lhs,
Register rhs);
@@ -181,9 +193,7 @@
__ IncrementCounter(counters->fast_new_closure_total(), 1, r6, r7);
- int map_index = (language_mode_ == CLASSIC_MODE)
- ? Context::FUNCTION_MAP_INDEX
- : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+ int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
// Compute the function map in the current native context and set that
// as the map of the allocated object.
@@ -403,153 +413,6 @@
}
-static void GenerateFastCloneShallowArrayCommon(
- MacroAssembler* masm,
- int length,
- FastCloneShallowArrayStub::Mode mode,
- AllocationSiteMode allocation_site_mode,
- Label* fail) {
- // Registers on entry:
- //
- // r3: boilerplate literal array.
- ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
- // All sizes here are multiples of kPointerSize.
- int elements_size = 0;
- if (length > 0) {
- elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
- ? FixedDoubleArray::SizeFor(length)
- : FixedArray::SizeFor(length);
- }
-
- int size = JSArray::kSize;
- int allocation_info_start = size;
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- size += AllocationSiteInfo::kSize;
- }
- size += elements_size;
-
- // Allocate both the JS array and the elements array in one big
- // allocation. This avoids multiple limit checks.
- AllocationFlags flags = TAG_OBJECT;
- if (mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS) {
- flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT | flags);
- }
- __ Allocate(size, r0, r1, r2, fail, flags);
-
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ mov(r2, Operand(Handle<Map>(masm->isolate()->heap()->
- allocation_site_info_map())));
- __ str(r2, FieldMemOperand(r0, allocation_info_start));
- __ str(r3, FieldMemOperand(r0, allocation_info_start + kPointerSize));
- }
-
- // Copy the JS array part.
- for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
- if ((i != JSArray::kElementsOffset) || (length == 0)) {
- __ ldr(r1, FieldMemOperand(r3, i));
- __ str(r1, FieldMemOperand(r0, i));
- }
- }
-
- if (length > 0) {
- // Get hold of the elements array of the boilerplate and setup the
- // elements pointer in the resulting object.
- __ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset));
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ add(r2, r0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
- } else {
- __ add(r2, r0, Operand(JSArray::kSize));
- }
- __ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset));
-
- // Copy the elements array.
- ASSERT((elements_size % kPointerSize) == 0);
- __ CopyFields(r2, r3, r1.bit(), elements_size / kPointerSize);
- }
-}
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
- // Stack layout on entry:
- //
- // [sp]: constant elements.
- // [sp + kPointerSize]: literal index.
- // [sp + (2 * kPointerSize)]: literals array.
-
- // Load boilerplate object into r3 and check if we need to create a
- // boilerplate.
- Label slow_case;
- __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
- __ ldr(r0, MemOperand(sp, 1 * kPointerSize));
- __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ ldr(r3, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
- __ b(eq, &slow_case);
-
- FastCloneShallowArrayStub::Mode mode = mode_;
- if (mode == CLONE_ANY_ELEMENTS) {
- Label double_elements, check_fast_elements;
- __ ldr(r0, FieldMemOperand(r3, JSArray::kElementsOffset));
- __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
- __ CompareRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
- __ b(ne, &check_fast_elements);
- GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- // Return and remove the on-stack parameters.
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
-
- __ bind(&check_fast_elements);
- __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
- __ b(ne, &double_elements);
- GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- // Return and remove the on-stack parameters.
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
-
- __ bind(&double_elements);
- mode = CLONE_DOUBLE_ELEMENTS;
- // Fall through to generate the code to handle double elements.
- }
-
- if (FLAG_debug_code) {
- const char* message;
- Heap::RootListIndex expected_map_index;
- if (mode == CLONE_ELEMENTS) {
- message = "Expected (writable) fixed array";
- expected_map_index = Heap::kFixedArrayMapRootIndex;
- } else if (mode == CLONE_DOUBLE_ELEMENTS) {
- message = "Expected (writable) fixed double array";
- expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
- } else {
- ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
- message = "Expected copy-on-write fixed array";
- expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
- }
- __ push(r3);
- __ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset));
- __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ CompareRoot(r3, expected_map_index);
- __ Assert(eq, message);
- __ pop(r3);
- }
-
- GenerateFastCloneShallowArrayCommon(masm, length_, mode,
- allocation_site_mode_,
- &slow_case);
-
- // Return and remove the on-stack parameters.
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
-
- __ bind(&slow_case);
- __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
// Takes a Smi and converts to an IEEE 64 bit floating point value in two
// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
@@ -650,30 +513,15 @@
FloatingPointHelper::Destination destination,
Register scratch1,
Register scratch2) {
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
- __ vmov(d7.high(), scratch1);
- __ vcvt_f64_s32(d7, d7.high());
- __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
- __ vmov(d6.high(), scratch1);
- __ vcvt_f64_s32(d6, d6.high());
- if (destination == kCoreRegisters) {
- __ vmov(r2, r3, d7);
- __ vmov(r0, r1, d6);
- }
- } else {
- ASSERT(destination == kCoreRegisters);
- // Write Smi from r0 to r3 and r2 in double format.
- __ mov(scratch1, Operand(r0));
- ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2);
- __ push(lr);
- __ Call(stub1.GetCode(masm->isolate()));
- // Write Smi from r1 to r1 and r0 in double format.
- __ mov(scratch1, Operand(r1));
- ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2);
- __ Call(stub2.GetCode(masm->isolate()));
- __ pop(lr);
+ __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
+ __ vmov(d7.high(), scratch1);
+ __ vcvt_f64_s32(d7, d7.high());
+ __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
+ __ vmov(d6.high(), scratch1);
+ __ vcvt_f64_s32(d6, d6.high());
+ if (destination == kCoreRegisters) {
+ __ vmov(r2, r3, d7);
+ __ vmov(r0, r1, d6);
}
}
@@ -700,9 +548,7 @@
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
// Handle loading a double from a heap number.
- if (CpuFeatures::IsSupported(VFP2) &&
- destination == kVFPRegisters) {
- CpuFeatureScope scope(masm, VFP2);
+ if (destination == kVFPRegisters) {
// Load the double from tagged HeapNumber to double register.
__ sub(scratch1, object, Operand(kHeapObjectTag));
__ vldr(dst, scratch1, HeapNumber::kValueOffset);
@@ -715,23 +561,12 @@
// Handle loading a double from a smi.
__ bind(&is_smi);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- // Convert smi to double using VFP instructions.
- __ vmov(dst.high(), scratch1);
- __ vcvt_f64_s32(dst, dst.high());
- if (destination == kCoreRegisters) {
- // Load the converted smi to dst1 and dst2 in double format.
- __ vmov(dst1, dst2, dst);
- }
- } else {
- ASSERT(destination == kCoreRegisters);
- // Write smi to dst1 and dst2 double format.
- __ mov(scratch1, Operand(object));
- ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
- __ push(lr);
- __ Call(stub.GetCode(masm->isolate()));
- __ pop(lr);
+ // Convert smi to double using VFP instructions.
+ __ vmov(dst.high(), scratch1);
+ __ vcvt_f64_s32(dst, dst.high());
+ if (destination == kCoreRegisters) {
+ // Load the converted smi to dst1 and dst2 in double format.
+ __ vmov(dst1, dst2, dst);
}
__ bind(&done);
@@ -778,62 +613,10 @@
Label done;
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- __ vmov(single_scratch, int_scratch);
- __ vcvt_f64_s32(double_dst, single_scratch);
- if (destination == kCoreRegisters) {
- __ vmov(dst_mantissa, dst_exponent, double_dst);
- }
- } else {
- Label fewer_than_20_useful_bits;
- // Expected output:
- // | dst_exponent | dst_mantissa |
- // | s | exp | mantissa |
-
- // Check for zero.
- __ cmp(int_scratch, Operand::Zero());
- __ mov(dst_exponent, int_scratch);
- __ mov(dst_mantissa, int_scratch);
- __ b(eq, &done);
-
- // Preload the sign of the value.
- __ and_(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask), SetCC);
- // Get the absolute value of the object (as an unsigned integer).
- __ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi);
-
- // Get mantissa[51:20].
-
- // Get the position of the first set bit.
- __ CountLeadingZeros(dst_mantissa, int_scratch, scratch2);
- __ rsb(dst_mantissa, dst_mantissa, Operand(31));
-
- // Set the exponent.
- __ add(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
- __ Bfi(dst_exponent, scratch2, scratch2,
- HeapNumber::kExponentShift, HeapNumber::kExponentBits);
-
- // Clear the first non null bit.
- __ mov(scratch2, Operand(1));
- __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst_mantissa));
-
- __ cmp(dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
- // Get the number of bits to set in the lower part of the mantissa.
- __ sub(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord),
- SetCC);
- __ b(mi, &fewer_than_20_useful_bits);
- // Set the higher 20 bits of the mantissa.
- __ orr(dst_exponent, dst_exponent, Operand(int_scratch, LSR, scratch2));
- __ rsb(scratch2, scratch2, Operand(32));
- __ mov(dst_mantissa, Operand(int_scratch, LSL, scratch2));
- __ b(&done);
-
- __ bind(&fewer_than_20_useful_bits);
- __ rsb(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
- __ mov(scratch2, Operand(int_scratch, LSL, scratch2));
- __ orr(dst_exponent, dst_exponent, scratch2);
- // Set dst1 to 0.
- __ mov(dst_mantissa, Operand::Zero());
+ __ vmov(single_scratch, int_scratch);
+ __ vcvt_f64_s32(double_dst, single_scratch);
+ if (destination == kCoreRegisters) {
+ __ vmov(dst_mantissa, dst_exponent, double_dst);
}
__ bind(&done);
}
@@ -872,65 +655,17 @@
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
// Load the number.
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- // Load the double value.
- __ sub(scratch1, object, Operand(kHeapObjectTag));
- __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
+ // Load the double value.
+ __ sub(scratch1, object, Operand(kHeapObjectTag));
+ __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
- __ TestDoubleIsInt32(double_dst, double_scratch);
- // Jump to not_int32 if the operation did not succeed.
- __ b(ne, not_int32);
+ __ TestDoubleIsInt32(double_dst, double_scratch);
+ // Jump to not_int32 if the operation did not succeed.
+ __ b(ne, not_int32);
- if (destination == kCoreRegisters) {
- __ vmov(dst_mantissa, dst_exponent, double_dst);
- }
-
- } else {
- ASSERT(!scratch1.is(object) && !scratch2.is(object));
- // Load the double value in the destination registers.
- bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
- if (save_registers) {
- // Save both output registers, because the other one probably holds
- // an important value too.
- __ Push(dst_exponent, dst_mantissa);
- }
- __ Ldrd(dst_mantissa, dst_exponent,
- FieldMemOperand(object, HeapNumber::kValueOffset));
-
- // Check for 0 and -0.
- Label zero;
- __ bic(scratch1, dst_exponent, Operand(HeapNumber::kSignMask));
- __ orr(scratch1, scratch1, Operand(dst_mantissa));
- __ cmp(scratch1, Operand::Zero());
- __ b(eq, &zero);
-
- // Check that the value can be exactly represented by a 32-bit integer.
- // Jump to not_int32 if that's not the case.
- Label restore_input_and_miss;
- DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
- &restore_input_and_miss);
-
- // dst_* were trashed. Reload the double value.
- if (save_registers) {
- __ Pop(dst_exponent, dst_mantissa);
- }
- __ Ldrd(dst_mantissa, dst_exponent,
- FieldMemOperand(object, HeapNumber::kValueOffset));
- __ b(&done);
-
- __ bind(&restore_input_and_miss);
- if (save_registers) {
- __ Pop(dst_exponent, dst_mantissa);
- }
- __ b(not_int32);
-
- __ bind(&zero);
- if (save_registers) {
- __ Drop(2);
- }
+ if (destination == kCoreRegisters) {
+ __ vmov(dst_mantissa, dst_exponent, double_dst);
}
-
__ bind(&done);
}
@@ -963,43 +698,13 @@
// Object is a heap number.
// Convert the floating point value to a 32-bit integer.
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
+ // Load the double value.
+ __ sub(scratch1, object, Operand(kHeapObjectTag));
+ __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
- // Load the double value.
- __ sub(scratch1, object, Operand(kHeapObjectTag));
- __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
-
- __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
- // Jump to not_int32 if the operation did not succeed.
- __ b(ne, not_int32);
- } else {
- // Load the double value in the destination registers.
- __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
-
- // Check for 0 and -0.
- __ bic(dst, scratch1, Operand(HeapNumber::kSignMask));
- __ orr(dst, scratch2, Operand(dst));
- __ cmp(dst, Operand::Zero());
- __ b(eq, &done);
-
- DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
-
- // Registers state after DoubleIs32BitInteger.
- // dst: mantissa[51:20].
- // scratch2: 1
-
- // Shift back the higher bits of the mantissa.
- __ mov(dst, Operand(dst, LSR, scratch3));
- // Set the implicit first bit.
- __ rsb(scratch3, scratch3, Operand(32));
- __ orr(dst, dst, Operand(scratch2, LSL, scratch3));
- // Set the sign.
- __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
- __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
- }
+ __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
+ // Jump to not_int32 if the operation did not succeed.
+ __ b(ne, not_int32);
__ b(&done);
__ bind(&maybe_undefined);
@@ -1093,7 +798,6 @@
__ push(lr);
__ PrepareCallCFunction(0, 2, scratch);
if (masm->use_eabi_hardfloat()) {
- CpuFeatureScope scope(masm, VFP2);
__ vmov(d0, r0, r1);
__ vmov(d1, r2, r3);
}
@@ -1105,7 +809,6 @@
// Store answer in the overwritable heap number. Double returned in
// registers r0 and r1 or in d0.
if (masm->use_eabi_hardfloat()) {
- CpuFeatureScope scope(masm, VFP2);
__ vstr(d0,
FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
} else {
@@ -1318,23 +1021,11 @@
}
// Lhs is a smi, rhs is a number.
- if (CpuFeatures::IsSupported(VFP2)) {
- // Convert lhs to a double in d7.
- CpuFeatureScope scope(masm, VFP2);
- __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
- // Load the double from rhs, tagged HeapNumber r0, to d6.
- __ sub(r7, rhs, Operand(kHeapObjectTag));
- __ vldr(d6, r7, HeapNumber::kValueOffset);
- } else {
- __ push(lr);
- // Convert lhs to a double in r2, r3.
- __ mov(r7, Operand(lhs));
- ConvertToDoubleStub stub1(r3, r2, r7, r6);
- __ Call(stub1.GetCode(masm->isolate()));
- // Load rhs to a double in r0, r1.
- __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- __ pop(lr);
- }
+ // Convert lhs to a double in d7.
+ __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
+ // Load the double from rhs, tagged HeapNumber r0, to d6.
+ __ sub(r7, rhs, Operand(kHeapObjectTag));
+ __ vldr(d6, r7, HeapNumber::kValueOffset);
// We now have both loaded as doubles but we can skip the lhs nan check
// since it's a smi.
@@ -1358,23 +1049,11 @@
}
// Rhs is a smi, lhs is a heap number.
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- // Load the double from lhs, tagged HeapNumber r1, to d7.
- __ sub(r7, lhs, Operand(kHeapObjectTag));
- __ vldr(d7, r7, HeapNumber::kValueOffset);
- // Convert rhs to a double in d6 .
- __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
- } else {
- __ push(lr);
- // Load lhs to a double in r2, r3.
- __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
- // Convert rhs to a double in r0, r1.
- __ mov(r7, Operand(rhs));
- ConvertToDoubleStub stub2(r1, r0, r7, r6);
- __ Call(stub2.GetCode(masm->isolate()));
- __ pop(lr);
- }
+ // Load the double from lhs, tagged HeapNumber r1, to d7.
+ __ sub(r7, lhs, Operand(kHeapObjectTag));
+ __ vldr(d7, r7, HeapNumber::kValueOffset);
+ // Convert rhs to a double in d6 .
+ __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
// Fall through to both_loaded_as_doubles.
}
@@ -1431,60 +1110,6 @@
// See comment at call site.
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm,
- Condition cond) {
- bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
- Register rhs_exponent = exp_first ? r0 : r1;
- Register lhs_exponent = exp_first ? r2 : r3;
- Register rhs_mantissa = exp_first ? r1 : r0;
- Register lhs_mantissa = exp_first ? r3 : r2;
-
- // r0, r1, r2, r3 have the two doubles. Neither is a NaN.
- if (cond == eq) {
- // Doubles are not equal unless they have the same bit pattern.
- // Exception: 0 and -0.
- __ cmp(rhs_mantissa, Operand(lhs_mantissa));
- __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne);
- // Return non-zero if the numbers are unequal.
- __ Ret(ne);
-
- __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC);
- // If exponents are equal then return 0.
- __ Ret(eq);
-
- // Exponents are unequal. The only way we can return that the numbers
- // are equal is if one is -0 and the other is 0. We already dealt
- // with the case where both are -0 or both are 0.
- // We start by seeing if the mantissas (that are equal) or the bottom
- // 31 bits of the rhs exponent are non-zero. If so we return not
- // equal.
- __ orr(r4, lhs_mantissa, Operand(lhs_exponent, LSL, kSmiTagSize), SetCC);
- __ mov(r0, Operand(r4), LeaveCC, ne);
- __ Ret(ne);
- // Now they are equal if and only if the lhs exponent is zero in its
- // low 31 bits.
- __ mov(r0, Operand(rhs_exponent, LSL, kSmiTagSize));
- __ Ret();
- } else {
- // Call a native function to do a comparison between two non-NaNs.
- // Call C routine that may not cause GC or other trouble.
- __ push(lr);
- __ PrepareCallCFunction(0, 2, r5);
- if (masm->use_eabi_hardfloat()) {
- CpuFeatureScope scope(masm, VFP2);
- __ vmov(d0, r0, r1);
- __ vmov(d1, r2, r3);
- }
-
- AllowExternalCallThatCantCauseGC scope(masm);
- __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
- 0, 2);
- __ pop(pc); // Return.
- }
-}
-
-
-// See comment at call site.
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
Register lhs,
Register rhs) {
@@ -1547,16 +1172,10 @@
// Both are heap numbers. Load them up then jump to the code we have
// for that.
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- __ sub(r7, rhs, Operand(kHeapObjectTag));
- __ vldr(d6, r7, HeapNumber::kValueOffset);
- __ sub(r7, lhs, Operand(kHeapObjectTag));
- __ vldr(d7, r7, HeapNumber::kValueOffset);
- } else {
- __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
- __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- }
+ __ sub(r7, rhs, Operand(kHeapObjectTag));
+ __ vldr(d6, r7, HeapNumber::kValueOffset);
+ __ sub(r7, lhs, Operand(kHeapObjectTag));
+ __ vldr(d7, r7, HeapNumber::kValueOffset);
__ jmp(both_loaded_as_doubles);
}
@@ -1637,42 +1256,37 @@
Label load_result_from_cache;
if (!object_is_smi) {
__ JumpIfSmi(object, &is_smi);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- __ CheckMap(object,
- scratch1,
- Heap::kHeapNumberMapRootIndex,
- not_found,
- DONT_DO_SMI_CHECK);
+ __ CheckMap(object,
+ scratch1,
+ Heap::kHeapNumberMapRootIndex,
+ not_found,
+ DONT_DO_SMI_CHECK);
- STATIC_ASSERT(8 == kDoubleSize);
- __ add(scratch1,
- object,
- Operand(HeapNumber::kValueOffset - kHeapObjectTag));
- __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
- __ eor(scratch1, scratch1, Operand(scratch2));
- __ and_(scratch1, scratch1, Operand(mask));
+ STATIC_ASSERT(8 == kDoubleSize);
+ __ add(scratch1,
+ object,
+ Operand(HeapNumber::kValueOffset - kHeapObjectTag));
+ __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
+ __ eor(scratch1, scratch1, Operand(scratch2));
+ __ and_(scratch1, scratch1, Operand(mask));
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- __ add(scratch1,
- number_string_cache,
- Operand(scratch1, LSL, kPointerSizeLog2 + 1));
+ // Calculate address of entry in string cache: each entry consists
+ // of two pointer sized fields.
+ __ add(scratch1,
+ number_string_cache,
+ Operand(scratch1, LSL, kPointerSizeLog2 + 1));
- Register probe = mask;
- __ ldr(probe,
- FieldMemOperand(scratch1, FixedArray::kHeaderSize));
- __ JumpIfSmi(probe, not_found);
- __ sub(scratch2, object, Operand(kHeapObjectTag));
- __ vldr(d0, scratch2, HeapNumber::kValueOffset);
- __ sub(probe, probe, Operand(kHeapObjectTag));
- __ vldr(d1, probe, HeapNumber::kValueOffset);
- __ VFPCompareAndSetFlags(d0, d1);
- __ b(ne, not_found); // The cache did not contain this value.
- __ b(&load_result_from_cache);
- } else {
- __ b(not_found);
- }
+ Register probe = mask;
+ __ ldr(probe,
+ FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+ __ JumpIfSmi(probe, not_found);
+ __ sub(scratch2, object, Operand(kHeapObjectTag));
+ __ vldr(d0, scratch2, HeapNumber::kValueOffset);
+ __ sub(probe, probe, Operand(kHeapObjectTag));
+ __ vldr(d1, probe, HeapNumber::kValueOffset);
+ __ VFPCompareAndSetFlags(d0, d1);
+ __ b(ne, not_found); // The cache did not contain this value.
+ __ b(&load_result_from_cache);
}
__ bind(&is_smi);
@@ -1787,37 +1401,27 @@
// The arguments have been converted to doubles and stored in d6 and d7, if
// VFP3 is supported, or in r0, r1, r2, and r3.
Isolate* isolate = masm->isolate();
- if (CpuFeatures::IsSupported(VFP2)) {
- __ bind(&lhs_not_nan);
- CpuFeatureScope scope(masm, VFP2);
- Label no_nan;
- // ARMv7 VFP3 instructions to implement double precision comparison.
- __ VFPCompareAndSetFlags(d7, d6);
- Label nan;
- __ b(vs, &nan);
- __ mov(r0, Operand(EQUAL), LeaveCC, eq);
- __ mov(r0, Operand(LESS), LeaveCC, lt);
- __ mov(r0, Operand(GREATER), LeaveCC, gt);
- __ Ret();
+ __ bind(&lhs_not_nan);
+ Label no_nan;
+ // ARMv7 VFP3 instructions to implement double precision comparison.
+ __ VFPCompareAndSetFlags(d7, d6);
+ Label nan;
+ __ b(vs, &nan);
+ __ mov(r0, Operand(EQUAL), LeaveCC, eq);
+ __ mov(r0, Operand(LESS), LeaveCC, lt);
+ __ mov(r0, Operand(GREATER), LeaveCC, gt);
+ __ Ret();
- __ bind(&nan);
- // If one of the sides was a NaN then the v flag is set. Load r0 with
- // whatever it takes to make the comparison fail, since comparisons with NaN
- // always fail.
- if (cc == lt || cc == le) {
- __ mov(r0, Operand(GREATER));
- } else {
- __ mov(r0, Operand(LESS));
- }
- __ Ret();
+ __ bind(&nan);
+ // If one of the sides was a NaN then the v flag is set. Load r0 with
+ // whatever it takes to make the comparison fail, since comparisons with NaN
+ // always fail.
+ if (cc == lt || cc == le) {
+ __ mov(r0, Operand(GREATER));
} else {
- // Checks for NaN in the doubles we have loaded. Can return the answer or
- // fall through if neither is a NaN. Also binds lhs_not_nan.
- EmitNanCheck(masm, &lhs_not_nan, cc);
- // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the
- // answer. Never falls through.
- EmitTwoNonNanDoubleComparison(masm, cc);
+ __ mov(r0, Operand(LESS));
}
+ __ Ret();
__ bind(¬_smis);
// At this point we know we are dealing with two different objects,
@@ -1914,7 +1518,6 @@
// we cannot call anything that could cause a GC from this stub.
Label patch;
const Register map = r9.is(tos_) ? r7 : r9;
- const Register temp = map;
// undefined -> false.
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
@@ -1957,9 +1560,9 @@
if (types_.Contains(STRING)) {
// String value -> false iff empty.
- __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
- __ Ret(lt); // the string length is OK as the return value
+ __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
+ __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
+ __ Ret(lt); // the string length is OK as the return value
}
if (types_.Contains(HEAP_NUMBER)) {
@@ -1968,55 +1571,13 @@
__ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
__ b(ne, ¬_heap_number);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
-
- __ 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
- // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
- __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
- __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
- } else {
- Label done, not_nan, not_zero;
- __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
- // -0 maps to false:
- __ bic(
- temp, temp, Operand(HeapNumber::kSignMask, RelocInfo::NONE32), SetCC);
- __ b(ne, ¬_zero);
- // If exponent word is zero then the answer depends on the mantissa word.
- __ ldr(tos_, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
- __ jmp(&done);
-
- // Check for NaN.
- __ bind(¬_zero);
- // We already zeroed the sign bit, now shift out the mantissa so we only
- // have the exponent left.
- __ mov(temp, Operand(temp, LSR, HeapNumber::kMantissaBitsInTopWord));
- unsigned int shifted_exponent_mask =
- HeapNumber::kExponentMask >> HeapNumber::kMantissaBitsInTopWord;
- __ cmp(temp, Operand(shifted_exponent_mask, RelocInfo::NONE32));
- __ b(ne, ¬_nan); // If exponent is not 0x7ff then it can't be a NaN.
-
- // Reload exponent word.
- __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
- __ tst(temp, Operand(HeapNumber::kMantissaMask, RelocInfo::NONE32));
- // If mantissa is not zero then we have a NaN, so return 0.
- __ mov(tos_, Operand::Zero(), LeaveCC, ne);
- __ b(ne, &done);
-
- // Load mantissa word.
- __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
- __ cmp(temp, Operand::Zero());
- // If mantissa is not zero then we have a NaN, so return 0.
- __ mov(tos_, Operand::Zero(), LeaveCC, ne);
- __ b(ne, &done);
-
- __ bind(¬_nan);
- __ mov(tos_, Operand(1, RelocInfo::NONE32));
- __ bind(&done);
- }
+ __ 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
+ // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
+ __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
+ __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
__ Ret();
__ bind(¬_heap_number);
}
@@ -2069,7 +1630,6 @@
const Register scratch = r1;
if (save_doubles_ == kSaveFPRegs) {
- CpuFeatureScope scope(masm, VFP2);
// Check CPU flags for number of registers, setting the Z condition flag.
__ CheckFor32DRegs(scratch);
@@ -2089,8 +1649,6 @@
ExternalReference::store_buffer_overflow_function(masm->isolate()),
argument_count);
if (save_doubles_ == kSaveFPRegs) {
- CpuFeatureScope scope(masm, VFP2);
-
// Check CPU flags for number of registers, setting the Z condition flag.
__ CheckFor32DRegs(scratch);
@@ -2315,19 +1873,10 @@
__ bind(&heapnumber_allocated);
}
- if (CpuFeatures::IsSupported(VFP2)) {
- // Convert the int32 in r1 to the heap number in r0. r2 is corrupted.
- CpuFeatureScope scope(masm, VFP2);
- __ vmov(s0, r1);
- __ vcvt_f64_s32(d0, s0);
- __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
- __ Ret();
- } else {
- // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
- // have to set up a frame.
- WriteInt32ToHeapNumberStub stub(r1, r0, r2);
- __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
- }
+ __ vmov(s0, r1);
+ __ vcvt_f64_s32(d0, s0);
+ __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+ __ Ret();
}
@@ -2383,7 +1932,7 @@
void BinaryOpStub::Initialize() {
- platform_specific_bit_ = CpuFeatures::IsSupported(VFP2);
+ platform_specific_bit_ = true; // VFP2 is a base requirement for V8
}
@@ -2662,7 +2211,6 @@
// Load left and right operands into d6 and d7 or r0/r1 and r2/r3
// depending on whether VFP3 is available or not.
FloatingPointHelper::Destination destination =
- CpuFeatures::IsSupported(VFP2) &&
op != Token::MOD ?
FloatingPointHelper::kVFPRegisters :
FloatingPointHelper::kCoreRegisters;
@@ -2706,7 +2254,6 @@
// Using VFP registers:
// d6: Left value
// d7: Right value
- CpuFeatureScope scope(masm, VFP2);
switch (op) {
case Token::ADD:
__ vadd(d5, d6, d7);
@@ -2797,11 +2344,7 @@
// The code below for writing into heap numbers isn't capable of
// writing the register as an unsigned int so we go to slow case if we
// hit this case.
- if (CpuFeatures::IsSupported(VFP2)) {
- __ b(mi, &result_not_a_smi);
- } else {
- __ b(mi, not_numbers);
- }
+ __ b(mi, &result_not_a_smi);
break;
case Token::SHL:
// Use only the 5 least significant bits of the shift count.
@@ -2837,25 +2380,17 @@
// result.
__ mov(r0, Operand(r5));
- if (CpuFeatures::IsSupported(VFP2)) {
- // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
- // mentioned above SHR needs to always produce a positive result.
- CpuFeatureScope scope(masm, VFP2);
- __ vmov(s0, r2);
- if (op == Token::SHR) {
- __ vcvt_f64_u32(d0, s0);
- } else {
- __ vcvt_f64_s32(d0, s0);
- }
- __ sub(r3, r0, Operand(kHeapObjectTag));
- __ vstr(d0, r3, HeapNumber::kValueOffset);
- __ Ret();
+ // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
+ // mentioned above SHR needs to always produce a positive result.
+ __ vmov(s0, r2);
+ if (op == Token::SHR) {
+ __ vcvt_f64_u32(d0, s0);
} else {
- // Tail call that writes the int32 in r2 to the heap number in r0, using
- // r3 as scratch. r0 is preserved and returned.
- WriteInt32ToHeapNumberStub stub(r2, r0, r3);
- __ TailCallStub(&stub);
+ __ vcvt_f64_s32(d0, s0);
}
+ __ sub(r3, r0, Operand(kHeapObjectTag));
+ __ vstr(d0, r3, HeapNumber::kValueOffset);
+ __ Ret();
break;
}
default:
@@ -3001,8 +2536,7 @@
// Load both operands and check that they are 32-bit integer.
// Jump to type transition if they are not. The registers r0 and r1 (right
// and left) are preserved for the runtime call.
- FloatingPointHelper::Destination destination =
- (CpuFeatures::IsSupported(VFP2) && op_ != Token::MOD)
+ FloatingPointHelper::Destination destination = (op_ != Token::MOD)
? FloatingPointHelper::kVFPRegisters
: FloatingPointHelper::kCoreRegisters;
@@ -3032,7 +2566,6 @@
&transition);
if (destination == FloatingPointHelper::kVFPRegisters) {
- CpuFeatureScope scope(masm, VFP2);
Label return_heap_number;
switch (op_) {
case Token::ADD:
@@ -3200,17 +2733,9 @@
// We only get a negative result if the shift value (r2) is 0.
// This result cannot be respresented as a signed 32-bit integer, try
// to return a heap number if we can.
- // The non vfp2 code does not support this special case, so jump to
- // runtime if we don't support it.
- if (CpuFeatures::IsSupported(VFP2)) {
- __ b(mi, (result_type_ <= BinaryOpIC::INT32)
- ? &transition
- : &return_heap_number);
- } else {
- __ b(mi, (result_type_ <= BinaryOpIC::INT32)
- ? &transition
- : &call_runtime);
- }
+ __ b(mi, (result_type_ <= BinaryOpIC::INT32)
+ ? &transition
+ : &return_heap_number);
break;
case Token::SHL:
__ and_(r2, r2, Operand(0x1f));
@@ -3238,31 +2763,22 @@
&call_runtime,
mode_);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- if (op_ != Token::SHR) {
- // Convert the result to a floating point value.
- __ vmov(double_scratch.low(), r2);
- __ vcvt_f64_s32(double_scratch, double_scratch.low());
- } else {
- // The result must be interpreted as an unsigned 32-bit integer.
- __ vmov(double_scratch.low(), r2);
- __ vcvt_f64_u32(double_scratch, double_scratch.low());
- }
-
- // Store the result.
- __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
- __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
- __ mov(r0, heap_number_result);
- __ Ret();
+ if (op_ != Token::SHR) {
+ // Convert the result to a floating point value.
+ __ vmov(double_scratch.low(), r2);
+ __ vcvt_f64_s32(double_scratch, double_scratch.low());
} else {
- // Tail call that writes the int32 in r2 to the heap number in r0, using
- // r3 as scratch. r0 is preserved and returned.
- __ mov(r0, r5);
- WriteInt32ToHeapNumberStub stub(r2, r0, r3);
- __ TailCallStub(&stub);
+ // The result must be interpreted as an unsigned 32-bit integer.
+ __ vmov(double_scratch.low(), r2);
+ __ vcvt_f64_u32(double_scratch, double_scratch.low());
}
+ // Store the result.
+ __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
+ __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
+ __ mov(r0, heap_number_result);
+ __ Ret();
+
break;
}
@@ -3441,100 +2957,96 @@
const Register cache_entry = r0;
const bool tagged = (argument_type_ == TAGGED);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- if (tagged) {
- // Argument is a number and is on stack and in r0.
- // Load argument and check if it is a smi.
- __ JumpIfNotSmi(r0, &input_not_smi);
+ if (tagged) {
+ // Argument is a number and is on stack and in r0.
+ // Load argument and check if it is a smi.
+ __ JumpIfNotSmi(r0, &input_not_smi);
- // Input is a smi. Convert to double and load the low and high words
- // of the double into r2, r3.
- __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
- __ b(&loaded);
+ // Input is a smi. Convert to double and load the low and high words
+ // of the double into r2, r3.
+ __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
+ __ b(&loaded);
- __ bind(&input_not_smi);
- // Check if input is a HeapNumber.
- __ CheckMap(r0,
- r1,
- Heap::kHeapNumberMapRootIndex,
- &calculate,
- DONT_DO_SMI_CHECK);
- // Input is a HeapNumber. Load it to a double register and store the
- // low and high words into r2, r3.
- __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
- __ vmov(r2, r3, d0);
- } else {
- // Input is untagged double in d2. Output goes to d2.
- __ vmov(r2, r3, d2);
- }
- __ bind(&loaded);
- // r2 = low 32 bits of double value
- // r3 = high 32 bits of double value
- // Compute hash (the shifts are arithmetic):
- // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
- __ eor(r1, r2, Operand(r3));
- __ eor(r1, r1, Operand(r1, ASR, 16));
- __ eor(r1, r1, Operand(r1, ASR, 8));
- ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
- __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
+ __ bind(&input_not_smi);
+ // Check if input is a HeapNumber.
+ __ CheckMap(r0,
+ r1,
+ Heap::kHeapNumberMapRootIndex,
+ &calculate,
+ DONT_DO_SMI_CHECK);
+ // Input is a HeapNumber. Load it to a double register and store the
+ // low and high words into r2, r3.
+ __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+ __ vmov(r2, r3, d0);
+ } else {
+ // Input is untagged double in d2. Output goes to d2.
+ __ vmov(r2, r3, d2);
+ }
+ __ bind(&loaded);
+ // r2 = low 32 bits of double value
+ // r3 = high 32 bits of double value
+ // Compute hash (the shifts are arithmetic):
+ // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
+ __ eor(r1, r2, Operand(r3));
+ __ eor(r1, r1, Operand(r1, ASR, 16));
+ __ eor(r1, r1, Operand(r1, ASR, 8));
+ ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+ __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
- // r2 = low 32 bits of double value.
- // r3 = high 32 bits of double value.
- // r1 = TranscendentalCache::hash(double value).
- Isolate* isolate = masm->isolate();
- ExternalReference cache_array =
- ExternalReference::transcendental_cache_array_address(isolate);
- __ mov(cache_entry, Operand(cache_array));
- // cache_entry points to cache array.
- int cache_array_index
- = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
- __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
- // r0 points to the cache for the type type_.
- // If NULL, the cache hasn't been initialized yet, so go through runtime.
- __ cmp(cache_entry, Operand::Zero());
- __ b(eq, &invalid_cache);
+ // r2 = low 32 bits of double value.
+ // r3 = high 32 bits of double value.
+ // r1 = TranscendentalCache::hash(double value).
+ Isolate* isolate = masm->isolate();
+ ExternalReference cache_array =
+ ExternalReference::transcendental_cache_array_address(isolate);
+ __ mov(cache_entry, Operand(cache_array));
+ // cache_entry points to cache array.
+ int cache_array_index
+ = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
+ __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
+ // r0 points to the cache for the type type_.
+ // If NULL, the cache hasn't been initialized yet, so go through runtime.
+ __ cmp(cache_entry, Operand::Zero());
+ __ b(eq, &invalid_cache);
#ifdef DEBUG
- // Check that the layout of cache elements match expectations.
- { TranscendentalCache::SubCache::Element test_elem[2];
- char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
- char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
- char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
- char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
- char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
- CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
- CHECK_EQ(0, elem_in0 - elem_start);
- CHECK_EQ(kIntSize, elem_in1 - elem_start);
- CHECK_EQ(2 * kIntSize, elem_out - elem_start);
- }
+ // Check that the layout of cache elements match expectations.
+ { TranscendentalCache::SubCache::Element test_elem[2];
+ char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
+ char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
+ char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
+ char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
+ char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
+ CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
+ CHECK_EQ(0, elem_in0 - elem_start);
+ CHECK_EQ(kIntSize, elem_in1 - elem_start);
+ CHECK_EQ(2 * kIntSize, elem_out - elem_start);
+ }
#endif
- // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
- __ add(r1, r1, Operand(r1, LSL, 1));
- __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
- // Check if cache matches: Double value is stored in uint32_t[2] array.
- __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
- __ cmp(r2, r4);
- __ cmp(r3, r5, eq);
- __ b(ne, &calculate);
- // Cache hit. Load result, cleanup and return.
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(
- counters->transcendental_cache_hit(), 1, scratch0, scratch1);
- if (tagged) {
- // Pop input value from stack and load result into r0.
- __ pop();
- __ mov(r0, Operand(r6));
- } else {
- // Load result into d2.
- __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
- }
- __ Ret();
- } // if (CpuFeatures::IsSupported(VFP3))
+ // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
+ __ add(r1, r1, Operand(r1, LSL, 1));
+ __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
+ // Check if cache matches: Double value is stored in uint32_t[2] array.
+ __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
+ __ cmp(r2, r4);
+ __ cmp(r3, r5, eq);
+ __ b(ne, &calculate);
+ // Cache hit. Load result, cleanup and return.
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(
+ counters->transcendental_cache_hit(), 1, scratch0, scratch1);
+ if (tagged) {
+ // Pop input value from stack and load result into r0.
+ __ pop();
+ __ mov(r0, Operand(r6));
+ } else {
+ // Load result into d2.
+ __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
+ }
+ __ Ret();
__ bind(&calculate);
- Counters* counters = masm->isolate()->counters();
__ IncrementCounter(
counters->transcendental_cache_miss(), 1, scratch0, scratch1);
if (tagged) {
@@ -3543,9 +3055,6 @@
ExternalReference(RuntimeFunction(), masm->isolate());
__ TailCallExternalReference(runtime_function, 1, 1);
} else {
- ASSERT(CpuFeatures::IsSupported(VFP2));
- CpuFeatureScope scope(masm, VFP2);
-
Label no_update;
Label skip_cache;
@@ -3605,7 +3114,6 @@
void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
Register scratch) {
- ASSERT(masm->IsEnabled(VFP2));
Isolate* isolate = masm->isolate();
__ push(lr);
@@ -3666,7 +3174,6 @@
void MathPowStub::Generate(MacroAssembler* masm) {
- CpuFeatureScope vfp2_scope(masm, VFP2);
const Register base = r1;
const Register exponent = r2;
const Register heapnumbermap = r5;
@@ -3879,14 +3386,13 @@
CEntryStub::GenerateAheadOfTime(isolate);
WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+ StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
}
void CodeStub::GenerateFPStubs(Isolate* isolate) {
- SaveFPRegsMode mode = CpuFeatures::IsSupported(VFP2)
- ? kSaveFPRegs
- : kDontSaveFPRegs;
+ SaveFPRegsMode mode = kSaveFPRegs;
CEntryStub save_doubles(1, mode);
StoreBufferOverflowStub stub(mode);
// These stubs might already be in the snapshot, detect that and don't
@@ -3895,11 +3401,13 @@
Code* save_doubles_code;
if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
save_doubles_code = *save_doubles.GetCode(isolate);
- save_doubles_code->set_is_pregenerated(true);
-
- Code* store_buffer_overflow_code = *stub.GetCode(isolate);
- store_buffer_overflow_code->set_is_pregenerated(true);
}
+ Code* store_buffer_overflow_code;
+ if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
+ store_buffer_overflow_code = *stub.GetCode(isolate);
+ }
+ save_doubles_code->set_is_pregenerated(true);
+ store_buffer_overflow_code->set_is_pregenerated(true);
isolate->set_fp_stubs_generated(true);
}
@@ -3989,6 +3497,8 @@
masm->Jump(r5);
}
+ __ VFPEnsureFPSCRState(r2);
+
if (always_allocate) {
// It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
// though (contain the result).
@@ -4024,11 +3534,18 @@
// Special handling of out of memory exceptions.
JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
- // Retrieve the pending exception and clear the variable.
- __ mov(r3, Operand(isolate->factory()->the_hole_value()));
+ // Retrieve the pending exception.
__ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ ldr(r0, MemOperand(ip));
+
+ // See if we just retrieved an OOM exception.
+ JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
+
+ // Clear the pending exception.
+ __ mov(r3, Operand(isolate->factory()->the_hole_value()));
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+ isolate)));
__ str(r3, MemOperand(ip));
// Special handling of termination exceptions which are uncatchable
@@ -4146,13 +3663,11 @@
// Save callee-saved registers (incl. cp and fp), sp, and lr
__ stm(db_w, sp, kCalleeSaved | lr.bit());
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- // Save callee-saved vfp registers.
- __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
- // Set up the reserved register for 0.0.
- __ vmov(kDoubleRegZero, 0.0);
- }
+ // Save callee-saved vfp registers.
+ __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
+ // Set up the reserved register for 0.0.
+ __ vmov(kDoubleRegZero, 0.0);
+ __ VFPEnsureFPSCRState(r4);
// Get address of argv, see stm above.
// r0: code entry
@@ -4162,9 +3677,7 @@
// Set up argv in r4.
int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
- if (CpuFeatures::IsSupported(VFP2)) {
- offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
- }
+ offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
__ ldr(r4, MemOperand(sp, offset_to_argv));
// Push a frame with special values setup to mark it as an entry frame.
@@ -4300,11 +3813,8 @@
}
#endif
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- // Restore callee-saved vfp registers.
- __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
- }
+ // Restore callee-saved vfp registers.
+ __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
__ ldm(ia_w, sp, kCalleeSaved | pc.bit());
}
@@ -4948,7 +4458,7 @@
Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX)));
// Copy the JS object part.
- __ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize);
+ __ CopyFields(r0, r4, d0, s0, JSObject::kHeaderSize / kPointerSize);
// Get the length (smi tagged) and set that as an in-object property too.
STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
@@ -7009,50 +6519,46 @@
}
// Inlining the double comparison and falling back to the general compare
- // stub if NaN is involved or VFP2 is unsupported.
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
+ // stub if NaN is involved.
+ // Load left and right operand.
+ Label done, left, left_smi, right_smi;
+ __ JumpIfSmi(r0, &right_smi);
+ __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
+ DONT_DO_SMI_CHECK);
+ __ sub(r2, r0, Operand(kHeapObjectTag));
+ __ vldr(d1, r2, HeapNumber::kValueOffset);
+ __ b(&left);
+ __ bind(&right_smi);
+ __ SmiUntag(r2, r0); // Can't clobber r0 yet.
+ SwVfpRegister single_scratch = d2.low();
+ __ vmov(single_scratch, r2);
+ __ vcvt_f64_s32(d1, single_scratch);
- // Load left and right operand.
- Label done, left, left_smi, right_smi;
- __ JumpIfSmi(r0, &right_smi);
- __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
- DONT_DO_SMI_CHECK);
- __ sub(r2, r0, Operand(kHeapObjectTag));
- __ vldr(d1, r2, HeapNumber::kValueOffset);
- __ b(&left);
- __ bind(&right_smi);
- __ SmiUntag(r2, r0); // Can't clobber r0 yet.
- SwVfpRegister single_scratch = d2.low();
- __ vmov(single_scratch, r2);
- __ vcvt_f64_s32(d1, single_scratch);
+ __ bind(&left);
+ __ JumpIfSmi(r1, &left_smi);
+ __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
+ DONT_DO_SMI_CHECK);
+ __ sub(r2, r1, Operand(kHeapObjectTag));
+ __ vldr(d0, r2, HeapNumber::kValueOffset);
+ __ b(&done);
+ __ bind(&left_smi);
+ __ SmiUntag(r2, r1); // Can't clobber r1 yet.
+ single_scratch = d3.low();
+ __ vmov(single_scratch, r2);
+ __ vcvt_f64_s32(d0, single_scratch);
- __ bind(&left);
- __ JumpIfSmi(r1, &left_smi);
- __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
- DONT_DO_SMI_CHECK);
- __ sub(r2, r1, Operand(kHeapObjectTag));
- __ vldr(d0, r2, HeapNumber::kValueOffset);
- __ b(&done);
- __ bind(&left_smi);
- __ SmiUntag(r2, r1); // Can't clobber r1 yet.
- single_scratch = d3.low();
- __ vmov(single_scratch, r2);
- __ vcvt_f64_s32(d0, single_scratch);
+ __ bind(&done);
+ // Compare operands.
+ __ VFPCompareAndSetFlags(d0, d1);
- __ bind(&done);
- // Compare operands.
- __ VFPCompareAndSetFlags(d0, d1);
+ // Don't base result on status bits when a NaN is involved.
+ __ b(vs, &unordered);
- // Don't base result on status bits when a NaN is involved.
- __ b(vs, &unordered);
-
- // Return a result of -1, 0, or 1, based on status bits.
- __ mov(r0, Operand(EQUAL), LeaveCC, eq);
- __ mov(r0, Operand(LESS), LeaveCC, lt);
- __ mov(r0, Operand(GREATER), LeaveCC, gt);
- __ Ret();
- }
+ // Return a result of -1, 0, or 1, based on status bits.
+ __ mov(r0, Operand(EQUAL), LeaveCC, eq);
+ __ mov(r0, Operand(LESS), LeaveCC, lt);
+ __ mov(r0, Operand(GREATER), LeaveCC, gt);
+ __ Ret();
__ bind(&unordered);
__ bind(&generic_stub);
@@ -7343,6 +6849,7 @@
__ Jump(target); // Call the C++ function.
ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
masm->SizeOfCodeGeneratedSince(&start));
+ __ VFPEnsureFPSCRState(r2);
}
@@ -7662,11 +7169,6 @@
}
-bool StoreBufferOverflowStub::IsPregenerated() {
- return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated();
-}
-
-
void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
Isolate* isolate) {
StoreBufferOverflowStub stub1(kDontSaveFPRegs);
@@ -7689,7 +7191,7 @@
bool CodeStub::CanUseFPRegisters() {
- return CpuFeatures::IsSupported(VFP2);
+ return true; // VFP2 is a base requirement for V8
}
@@ -7948,16 +7450,14 @@
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
__ StoreNumberToDoubleElements(r0, r3,
// Overwrites all regs after this.
- r5, r6, r7, r9, r2,
+ r5, r9, r6, r7, r2,
&slow_elements);
__ Ret();
}
void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
- ASSERT(!Serializer::enabled());
- bool save_fp_regs = CpuFeatures::IsSupported(VFP2);
- CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
+ CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
__ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 61ecc97..741ff9c 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -61,11 +61,11 @@
class StoreBufferOverflowStub: public PlatformCodeStub {
public:
explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
- : save_doubles_(save_fp) { }
+ : save_doubles_(save_fp) {}
void Generate(MacroAssembler* masm);
- virtual bool IsPregenerated();
+ virtual bool IsPregenerated() { return true; }
static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
virtual bool SometimesSetsUpAFrame() { return false; }
@@ -471,7 +471,6 @@
if (mode == kSaveFPRegs) {
// Number of d-regs not known at snapshot time.
ASSERT(!Serializer::enabled());
- CpuFeatureScope scope(masm, VFP2);
masm->sub(sp,
sp,
Operand(kDoubleSize * (DwVfpRegister::NumRegisters() - 1)));
@@ -489,7 +488,6 @@
if (mode == kSaveFPRegs) {
// Number of d-regs not known at snapshot time.
ASSERT(!Serializer::enabled());
- CpuFeatureScope scope(masm, VFP2);
// Restore all VFP registers except d0.
// TODO(hans): We should probably restore d0 too. And maybe use vldm.
for (int i = DwVfpRegister::NumRegisters() - 1; i > 0; i--) {
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 1c82946..9d773d4 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -62,7 +62,6 @@
UnaryMathFunction CreateExpFunction() {
- if (!CpuFeatures::IsSupported(VFP2)) return &exp;
if (!FLAG_fast_math) return &exp;
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
@@ -72,7 +71,6 @@
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
{
- CpuFeatureScope use_vfp(&masm, VFP2);
DwVfpRegister input = d0;
DwVfpRegister result = d1;
DwVfpRegister double_scratch1 = d2;
@@ -185,7 +183,6 @@
// -- r4 : scratch (elements)
// -----------------------------------
Label loop, entry, convert_hole, gc_required, only_change_map, done;
- bool vfp2_supported = CpuFeatures::IsSupported(VFP2);
if (mode == TRACK_ALLOCATION_SITE) {
__ TestJSArrayForAllocationSiteInfo(r2, r4);
@@ -248,7 +245,6 @@
// r5: kHoleNanUpper32
// r6: end of destination FixedDoubleArray, not tagged
// r7: begin of FixedDoubleArray element fields, not tagged
- if (!vfp2_supported) __ Push(r1, r0);
__ b(&entry);
@@ -276,23 +272,10 @@
__ UntagAndJumpIfNotSmi(r9, r9, &convert_hole);
// Normal smi, convert to double and store.
- if (vfp2_supported) {
- CpuFeatureScope scope(masm, VFP2);
- __ vmov(s0, r9);
- __ vcvt_f64_s32(d0, s0);
- __ vstr(d0, r7, 0);
- __ add(r7, r7, Operand(8));
- } else {
- FloatingPointHelper::ConvertIntToDouble(masm,
- r9,
- FloatingPointHelper::kCoreRegisters,
- d0,
- r0,
- r1,
- lr,
- s0);
- __ Strd(r0, r1, MemOperand(r7, 8, PostIndex));
- }
+ __ vmov(s0, r9);
+ __ vcvt_f64_s32(d0, s0);
+ __ vstr(d0, r7, 0);
+ __ add(r7, r7, Operand(8));
__ b(&entry);
// Hole found, store the-hole NaN.
@@ -310,7 +293,6 @@
__ cmp(r7, r6);
__ b(lt, &loop);
- if (!vfp2_supported) __ Pop(r1, r0);
__ pop(lr);
__ bind(&done);
}
diff --git a/src/arm/constants-arm.cc b/src/arm/constants-arm.cc
index cdca1f5..a130484 100644
--- a/src/arm/constants-arm.cc
+++ b/src/arm/constants-arm.cc
@@ -51,7 +51,7 @@
uint64_t imm = high16 << 48;
double d;
- memcpy(&d, &imm, 8);
+ OS::MemCopy(&d, &imm, 8);
return d;
}
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index 004165a..747dc56 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -44,21 +44,25 @@
defined(__ARM_ARCH_7R__) || \
defined(__ARM_ARCH_7__)
# define CAN_USE_ARMV7_INSTRUCTIONS 1
+#ifndef CAN_USE_VFP3_INSTRUCTIONS
+# define CAN_USE_VFP3_INSTRUCTIONS
+#endif
#endif
-#if defined(__ARM_ARCH_6__) || \
- defined(__ARM_ARCH_6J__) || \
- defined(__ARM_ARCH_6K__) || \
- defined(__ARM_ARCH_6Z__) || \
+#if defined(__ARM_ARCH_6__) || \
+ defined(__ARM_ARCH_6J__) || \
+ defined(__ARM_ARCH_6K__) || \
+ defined(__ARM_ARCH_6Z__) || \
defined(__ARM_ARCH_6ZK__) || \
defined(__ARM_ARCH_6T2__) || \
defined(CAN_USE_ARMV7_INSTRUCTIONS)
# define CAN_USE_ARMV6_INSTRUCTIONS 1
#endif
-#if defined(__ARM_ARCH_5T__) || \
- defined(__ARM_ARCH_5TE__) || \
- defined(__ARM_ARCH_5TEJ__) || \
+#if defined(__ARM_ARCH_5__) || \
+ defined(__ARM_ARCH_5T__) || \
+ defined(__ARM_ARCH_5TE__) || \
+ defined(__ARM_ARCH_5TEJ__) || \
defined(CAN_USE_ARMV6_INSTRUCTIONS)
# define CAN_USE_ARMV5_INSTRUCTIONS 1
# define CAN_USE_THUMB_INSTRUCTIONS 1
@@ -403,6 +407,7 @@
const uint32_t kVFPUnderflowExceptionBit = 1 << 3;
const uint32_t kVFPInexactExceptionBit = 1 << 4;
const uint32_t kVFPFlushToZeroMask = 1 << 24;
+const uint32_t kVFPDefaultNaNModeControlBit = 1 << 25;
const uint32_t kVFPNConditionFlagBit = 1 << 31;
const uint32_t kVFPZConditionFlagBit = 1 << 30;
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 9bcc1ac..25ad85c 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -117,45 +117,39 @@
static const int32_t kBranchBeforeInterrupt = 0x5a000004;
+// The back edge bookkeeping code matches the pattern:
+//
+// <decrement profiling counter>
+// 2a 00 00 01 bpl ok
+// e5 9f c? ?? ldr ip, [pc, <interrupt stub address>]
+// e1 2f ff 3c blx ip
+// ok-label
+//
+// We patch the code to the following form:
+//
+// <decrement profiling counter>
+// e1 a0 00 00 mov r0, r0 (NOP)
+// e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>]
+// e1 2f ff 3c blx ip
+// ok-label
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
- const int kInstrSize = Assembler::kInstrSize;
- // The back edge bookkeeping code matches the pattern:
- //
- // <decrement profiling counter>
- // 2a 00 00 01 bpl ok
- // e5 9f c? ?? ldr ip, [pc, <stack guard address>]
- // e1 2f ff 3c blx ip
- ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
- ASSERT(Assembler::IsLdrPcImmediateOffset(
- Assembler::instr_at(pc_after - 2 * kInstrSize)));
- ASSERT_EQ(kBranchBeforeInterrupt,
- Memory::int32_at(pc_after - 3 * kInstrSize));
-
- // We patch the code to the following form:
- //
- // <decrement profiling counter>
- // e1 a0 00 00 mov r0, r0 (NOP)
- // e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>]
- // e1 2f ff 3c blx ip
- // and overwrite the constant containing the
- // address of the stack check stub.
-
- // Replace conditional jump with NOP.
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ static const int kInstrSize = Assembler::kInstrSize;
+ // Turn the jump into nops.
CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
patcher.masm()->nop();
-
- // Replace the stack check address in the constant pool
- // with the entry address of the replacement code.
- uint32_t stack_check_address_offset = Memory::uint16_at(pc_after -
+ // Replace the call address.
+ uint32_t interrupt_address_offset = Memory::uint16_at(pc_after -
2 * kInstrSize) & 0xfff;
- Address stack_check_address_pointer = pc_after + stack_check_address_offset;
- ASSERT(Memory::uint32_at(stack_check_address_pointer) ==
- reinterpret_cast<uint32_t>(check_code->entry()));
- Memory::uint32_at(stack_check_address_pointer) =
+ Address interrupt_address_pointer = pc_after + interrupt_address_offset;
+ Memory::uint32_at(interrupt_address_pointer) =
reinterpret_cast<uint32_t>(replacement_code->entry());
unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
@@ -163,36 +157,63 @@
}
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
- const int kInstrSize = Assembler::kInstrSize;
- ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
- ASSERT(Assembler::IsLdrPcImmediateOffset(
- Assembler::instr_at(pc_after - 2 * kInstrSize)));
-
- // Replace NOP with conditional jump.
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ static const int kInstrSize = Assembler::kInstrSize;
+ // Restore the original jump.
CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
- patcher.masm()->b(+16, pl);
+ patcher.masm()->b(4 * kInstrSize, pl); // ok-label is 4 instructions later.
ASSERT_EQ(kBranchBeforeInterrupt,
Memory::int32_at(pc_after - 3 * kInstrSize));
-
- // Replace the stack check address in the constant pool
- // with the entry address of the replacement code.
- uint32_t stack_check_address_offset = Memory::uint16_at(pc_after -
+ // Restore the original call address.
+ uint32_t interrupt_address_offset = Memory::uint16_at(pc_after -
2 * kInstrSize) & 0xfff;
- Address stack_check_address_pointer = pc_after + stack_check_address_offset;
- ASSERT(Memory::uint32_at(stack_check_address_pointer) ==
- reinterpret_cast<uint32_t>(replacement_code->entry()));
- Memory::uint32_at(stack_check_address_pointer) =
- reinterpret_cast<uint32_t>(check_code->entry());
+ Address interrupt_address_pointer = pc_after + interrupt_address_offset;
+ Memory::uint32_at(interrupt_address_pointer) =
+ reinterpret_cast<uint32_t>(interrupt_code->entry());
- check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
- unoptimized_code, pc_after - 2 * kInstrSize, check_code);
+ interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+ unoptimized_code, pc_after - 2 * kInstrSize, interrupt_code);
}
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ static const int kInstrSize = Assembler::kInstrSize;
+ ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
+
+ uint32_t interrupt_address_offset =
+ Memory::uint16_at(pc_after - 2 * kInstrSize) & 0xfff;
+ Address interrupt_address_pointer = pc_after + interrupt_address_offset;
+
+ if (Assembler::IsNop(Assembler::instr_at(pc_after - 3 * kInstrSize))) {
+ ASSERT(Assembler::IsLdrPcImmediateOffset(
+ Assembler::instr_at(pc_after - 2 * kInstrSize)));
+ ASSERT(reinterpret_cast<uint32_t>(replacement_code->entry()) ==
+ Memory::uint32_at(interrupt_address_pointer));
+ return true;
+ } else {
+ ASSERT(Assembler::IsLdrPcImmediateOffset(
+ Assembler::instr_at(pc_after - 2 * kInstrSize)));
+ ASSERT_EQ(kBranchBeforeInterrupt,
+ Memory::int32_at(pc_after - 3 * kInstrSize));
+ ASSERT(reinterpret_cast<uint32_t>(interrupt_code->entry()) ==
+ Memory::uint32_at(interrupt_address_pointer));
+ return false;
+ }
+}
+#endif // DEBUG
+
+
static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
ByteArray* translations = data->TranslationByteArray();
int length = data->DeoptCount();
@@ -594,23 +615,18 @@
const int kDoubleRegsSize =
kDoubleSize * DwVfpRegister::kMaxNumAllocatableRegisters;
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- // Save all allocatable VFP registers before messing with them.
- ASSERT(kDoubleRegZero.code() == 14);
- ASSERT(kScratchDoubleReg.code() == 15);
+ // Save all allocatable VFP registers before messing with them.
+ ASSERT(kDoubleRegZero.code() == 14);
+ ASSERT(kScratchDoubleReg.code() == 15);
- // Check CPU flags for number of registers, setting the Z condition flag.
- __ CheckFor32DRegs(ip);
+ // Check CPU flags for number of registers, setting the Z condition flag.
+ __ CheckFor32DRegs(ip);
- // Push registers d0-d13, and possibly d16-d31, on the stack.
- // If d16-d31 are not pushed, decrease the stack pointer instead.
- __ vstm(db_w, sp, d16, d31, ne);
- __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
- __ vstm(db_w, sp, d0, d13);
- } else {
- __ sub(sp, sp, Operand(kDoubleRegsSize));
- }
+ // Push registers d0-d13, and possibly d16-d31, on the stack.
+ // If d16-d31 are not pushed, decrease the stack pointer instead.
+ __ vstm(db_w, sp, d16, d31, ne);
+ __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
+ __ vstm(db_w, sp, d0, d13);
// Push all 16 registers (needed to populate FrameDescription::registers_).
// TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
@@ -669,17 +685,14 @@
__ str(r2, MemOperand(r1, offset));
}
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- // Copy VFP registers to
- // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
- int double_regs_offset = FrameDescription::double_registers_offset();
- for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
- int dst_offset = i * kDoubleSize + double_regs_offset;
- int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
- __ vldr(d0, sp, src_offset);
- __ vstr(d0, r1, dst_offset);
- }
+ // Copy VFP registers to
+ // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
+ int double_regs_offset = FrameDescription::double_registers_offset();
+ for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
+ int dst_offset = i * kDoubleSize + double_regs_offset;
+ int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
+ __ vldr(d0, sp, src_offset);
+ __ vstr(d0, r1, dst_offset);
}
// Remove the bailout id, eventually return address, and the saved registers
@@ -749,21 +762,18 @@
__ cmp(r4, r1);
__ b(lt, &outer_push_loop);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- // Check CPU flags for number of registers, setting the Z condition flag.
- __ CheckFor32DRegs(ip);
+ // Check CPU flags for number of registers, setting the Z condition flag.
+ __ CheckFor32DRegs(ip);
- __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
- int src_offset = FrameDescription::double_registers_offset();
- for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
- if (i == kDoubleRegZero.code()) continue;
- if (i == kScratchDoubleReg.code()) continue;
+ __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
+ int src_offset = FrameDescription::double_registers_offset();
+ for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
+ if (i == kDoubleRegZero.code()) continue;
+ if (i == kScratchDoubleReg.code()) continue;
- const DwVfpRegister reg = DwVfpRegister::from_code(i);
- __ vldr(reg, r1, src_offset, i < 16 ? al : ne);
- src_offset += kDoubleSize;
- }
+ const DwVfpRegister reg = DwVfpRegister::from_code(i);
+ __ vldr(reg, r1, src_offset, i < 16 ? al : ne);
+ src_offset += kDoubleSize;
}
// Push state, pc, and continuation from the last output frame.
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index dec62b3..b84d355 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -1561,8 +1561,9 @@
buffer[0] = '\0';
byte* prev_pc = pc;
pc += d.InstructionDecode(buffer, pc);
- fprintf(f, "%p %08x %s\n",
- prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
+ v8::internal::PrintF(
+ f, "%p %08x %s\n",
+ prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
}
}
diff --git a/src/arm/frames-arm.h b/src/arm/frames-arm.h
index 30f4057..19b29b8 100644
--- a/src/arm/frames-arm.h
+++ b/src/arm/frames-arm.h
@@ -100,18 +100,6 @@
// ----------------------------------------------------
-class StackHandlerConstants : public AllStatic {
- public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kCodeOffset = 1 * kPointerSize;
- static const int kStateOffset = 2 * kPointerSize;
- static const int kContextOffset = 3 * kPointerSize;
- static const int kFPOffset = 4 * kPointerSize;
-
- static const int kSize = kFPOffset + kPointerSize;
-};
-
-
class EntryFrameConstants : public AllStatic {
public:
static const int kCallerFPOffset = -3 * kPointerSize;
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 6086645..ba0f141 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -162,8 +162,6 @@
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
- int locals_count = info->scope()->num_stack_slots();
-
info->set_prologue_offset(masm_->pc_offset());
{
PredictableCodeSizeScope predictible_code_size_scope(
@@ -179,6 +177,9 @@
}
{ Comment cmnt(masm_, "[ Allocate locals");
+ int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
for (int i = 0; i < locals_count; i++) {
__ push(ip);
}
@@ -313,7 +314,7 @@
EmitReturnSequence();
// Force emit the constant pool, so it doesn't get emitted in the middle
- // of the stack check table.
+ // of the back edge table.
masm()->CheckConstPool(true, false);
}
@@ -350,7 +351,7 @@
void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
Label* back_edge_target) {
Comment cmnt(masm_, "[ Back edge bookkeeping");
- // Block literal pools whilst emitting stack check code.
+ // Block literal pools whilst emitting back edge code.
Assembler::BlockConstPoolScope block_const_pool(masm_);
Label ok;
@@ -1268,7 +1269,7 @@
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->language_mode());
+ FastNewClosureStub stub(info->language_mode(), info->is_generator());
__ mov(r0, Operand(info));
__ push(r0);
__ CallStub(&stub);
@@ -1562,7 +1563,7 @@
// r0: Newly allocated regexp.
// r5: Materialized regexp.
// r2: temp.
- __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
+ __ CopyFields(r0, r5, d0, s0, size / kPointerSize);
context()->Plug(r0);
}
@@ -1727,7 +1728,6 @@
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
__ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(constant_elements));
- __ Push(r3, r2, r1);
if (has_fast_elements && constant_elements_values->map() ==
isolate()->heap()->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
@@ -1738,8 +1738,11 @@
__ IncrementCounter(
isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
} else if (expr->depth() > 1) {
+ __ Push(r3, r2, r1);
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
- } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ } else if (Serializer::enabled() ||
+ length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ Push(r3, r2, r1);
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -3024,37 +3027,26 @@
// Convert 32 random bits in r0 to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
- if (CpuFeatures::IsSupported(VFP2)) {
- __ PrepareCallCFunction(1, r0);
- __ ldr(r0,
- ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
- __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+ __ PrepareCallCFunction(1, r0);
+ __ ldr(r0,
+ ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
+ __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
- CpuFeatureScope scope(masm(), VFP2);
- // 0x41300000 is the top half of 1.0 x 2^20 as a double.
- // Create this constant using mov/orr to avoid PC relative load.
- __ mov(r1, Operand(0x41000000));
- __ orr(r1, r1, Operand(0x300000));
- // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
- __ vmov(d7, r0, r1);
- // Move 0x4130000000000000 to VFP.
- __ mov(r0, Operand::Zero());
- __ vmov(d8, r0, r1);
- // Subtract and store the result in the heap number.
- __ vsub(d7, d7, d8);
- __ sub(r0, r4, Operand(kHeapObjectTag));
- __ vstr(d7, r0, HeapNumber::kValueOffset);
- __ mov(r0, r4);
- } else {
- __ PrepareCallCFunction(2, r0);
- __ ldr(r1,
- ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
- __ mov(r0, Operand(r4));
- __ ldr(r1, FieldMemOperand(r1, GlobalObject::kNativeContextOffset));
- __ CallCFunction(
- ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
- }
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ // Create this constant using mov/orr to avoid PC relative load.
+ __ mov(r1, Operand(0x41000000));
+ __ orr(r1, r1, Operand(0x300000));
+ // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
+ __ vmov(d7, r0, r1);
+ // Move 0x4130000000000000 to VFP.
+ __ mov(r0, Operand::Zero());
+ __ vmov(d8, r0, r1);
+ // Subtract and store the result in the heap number.
+ __ vsub(d7, d7, d8);
+ __ sub(r0, r4, Operand(kHeapObjectTag));
+ __ vstr(d7, r0, HeapNumber::kValueOffset);
+ __ mov(r0, r4);
context()->Plug(r0);
}
@@ -3191,12 +3183,8 @@
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- if (CpuFeatures::IsSupported(VFP2)) {
- MathPowStub stub(MathPowStub::ON_STACK);
- __ CallStub(&stub);
- } else {
- __ CallRuntime(Runtime::kMath_pow, 2);
- }
+ MathPowStub stub(MathPowStub::ON_STACK);
+ __ CallStub(&stub);
context()->Plug(r0);
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index f2b65ef..f6029b5 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -302,17 +302,6 @@
}
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
- stream->Add("/%s ", hydrogen()->OpName());
- value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
- value()->PrintTo(stream);
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -1124,47 +1113,101 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
- BuiltinFunctionId op = instr->op();
- if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
- LOperand* input = UseFixedDouble(instr->value(), d2);
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
- return MarkAsCall(DefineFixedDouble(result, d2), instr);
- } else if (op == kMathExp) {
- ASSERT(instr->representation().IsDouble());
- ASSERT(instr->value()->representation().IsDouble());
- LOperand* input = UseTempRegister(instr->value());
- LOperand* temp1 = TempRegister();
- LOperand* temp2 = TempRegister();
- LOperand* double_temp = FixedTemp(d3); // Chosen by fair dice roll.
- LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
- return DefineAsRegister(result);
- } else if (op == kMathPowHalf) {
- LOperand* input = UseFixedDouble(instr->value(), d2);
- LOperand* temp = FixedTemp(d3);
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
- return DefineFixedDouble(result, d2);
- } else {
- LOperand* input = UseRegister(instr->value());
-
- LOperand* temp = (op == kMathRound) ? FixedTemp(d3) : NULL;
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
- switch (op) {
- case kMathAbs:
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
- case kMathFloor:
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
- case kMathSqrt:
- return DefineAsRegister(result);
- case kMathRound:
- return AssignEnvironment(DefineAsRegister(result));
- default:
- UNREACHABLE();
- return NULL;
- }
+ switch (instr->op()) {
+ case kMathFloor: return DoMathFloor(instr);
+ case kMathRound: return DoMathRound(instr);
+ case kMathAbs: return DoMathAbs(instr);
+ case kMathLog: return DoMathLog(instr);
+ case kMathSin: return DoMathSin(instr);
+ case kMathCos: return DoMathCos(instr);
+ case kMathTan: return DoMathTan(instr);
+ case kMathExp: return DoMathExp(instr);
+ case kMathSqrt: return DoMathSqrt(instr);
+ case kMathPowHalf: return DoMathPowHalf(instr);
+ default:
+ UNREACHABLE();
+ return NULL;
}
}
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LMathFloor* result = new(zone()) LMathFloor(input);
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LOperand* temp = FixedTemp(d3);
+ LMathRound* result = new(zone()) LMathRound(input, temp);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LMathAbs* result = new(zone()) LMathAbs(input);
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), d2);
+ LMathLog* result = new(zone()) LMathLog(input);
+ return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), d2);
+ LMathSin* result = new(zone()) LMathSin(input);
+ return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), d2);
+ LMathCos* result = new(zone()) LMathCos(input);
+ return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), d2);
+ LMathTan* result = new(zone()) LMathTan(input);
+ return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* input = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LOperand* double_temp = FixedTemp(d3); // Chosen by fair dice roll.
+ LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
+ return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LMathSqrt* result = new(zone()) LMathSqrt(input);
+ return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), d2);
+ LOperand* temp = FixedTemp(d3);
+ LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
+ return DefineFixedDouble(result, d2);
+}
+
+
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
argument_count_ -= instr->argument_count();
@@ -1933,7 +1976,7 @@
LUnallocated* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2);
- return AssignEnvironment(Define(result, temp1));
+ return AssignEnvironment(result);
}
@@ -2133,16 +2176,7 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
- // float->double conversion on non-VFP2 requires an extra scratch
- // register. For convenience, just mark the elements register as "UseTemp"
- // so that it can be used as a temp during the float->double conversion
- // after it's no longer needed after the float load.
- bool needs_temp =
- !CpuFeatures::IsSupported(VFP2) &&
- (elements_kind == EXTERNAL_FLOAT_ELEMENTS);
- LOperand* external_pointer = needs_temp
- ? UseTempRegister(instr->elements())
- : UseRegister(instr->elements());
+ LOperand* external_pointer = UseRegister(instr->elements());
result = new(zone()) LLoadKeyed(external_pointer, key);
}
@@ -2341,11 +2375,6 @@
}
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
- return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, r0), instr);
-}
-
-
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, r0), instr);
}
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 207faf4..6486cad 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -97,7 +97,6 @@
V(DoubleToI) \
V(DummyUse) \
V(ElementsKind) \
- V(FastLiteral) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
@@ -134,9 +133,18 @@
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
+ V(MathAbs) \
+ V(MathCos) \
V(MathExp) \
+ V(MathFloor) \
V(MathFloorOfDiv) \
+ V(MathLog) \
V(MathMinMax) \
+ V(MathPowHalf) \
+ V(MathRound) \
+ V(MathSin) \
+ V(MathSqrt) \
+ V(MathTan) \
V(ModI) \
V(MulI) \
V(MultiplyAddD) \
@@ -181,7 +189,6 @@
V(TrapAllocationMemento) \
V(Typeof) \
V(TypeofIsAndBranch) \
- V(UnaryMathOperation) \
V(UnknownOSRValue) \
V(ValueOf) \
V(ForInPrepareMap) \
@@ -703,9 +710,22 @@
};
-class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
+class LMathFloor: public LTemplateInstruction<1, 1, 0> {
public:
- LUnaryMathOperation(LOperand* value, LOperand* temp) {
+ explicit LMathFloor(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathRound: public LTemplateInstruction<1, 1, 1> {
+ public:
+ LMathRound(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
@@ -713,11 +733,69 @@
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
- DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+ DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
- virtual void PrintDataTo(StringStream* stream);
- BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathAbs: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathAbs(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathLog(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSin(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathCos(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathTan(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
};
@@ -740,8 +818,32 @@
LOperand* double_temp() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
- virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSqrt(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf: public LTemplateInstruction<1, 1, 1> {
+ public:
+ LMathPowHalf(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
};
@@ -1310,7 +1412,7 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+ DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
};
@@ -2074,7 +2176,13 @@
DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
virtual void PrintDataTo(StringStream* stream);
- bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
+ bool NeedsCanonicalization() {
+ if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() ||
+ hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) {
+ return false;
+ }
+ return hydrogen()->NeedsCanonicalization();
+ }
uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -2239,7 +2347,7 @@
};
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
public:
LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) {
temps_[0] = temp;
@@ -2355,13 +2463,6 @@
};
-class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
- public:
- DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
- DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
@@ -2611,6 +2712,17 @@
static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
+ LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+ LInstruction* DoMathRound(HUnaryMathOperation* instr);
+ LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+ LInstruction* DoMathLog(HUnaryMathOperation* instr);
+ LInstruction* DoMathSin(HUnaryMathOperation* instr);
+ LInstruction* DoMathCos(HUnaryMathOperation* instr);
+ LInstruction* DoMathTan(HUnaryMathOperation* instr);
+ LInstruction* DoMathExp(HUnaryMathOperation* instr);
+ LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+ LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
private:
enum Status {
UNUSED,
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 7bb3535..a19015d 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -113,7 +113,7 @@
// issues when the stack allocated buffer goes out of scope.
size_t length = builder.position();
Vector<char> copy = Vector<char>::New(length + 1);
- memcpy(copy.start(), builder.Finalize(), copy.length());
+ OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
masm()->RecordComment(copy.start());
}
@@ -195,8 +195,7 @@
}
}
- if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
+ if (info()->saves_caller_doubles()) {
Comment(";;; Save clobbered callee double registers");
int count = 0;
BitVector* doubles = chunk()->allocated_double_registers();
@@ -852,7 +851,9 @@
}
ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM.
- if (FLAG_deopt_every_n_times == 1 && info_->opt_count() == id) {
+ if (FLAG_deopt_every_n_times == 1 &&
+ !info()->IsStub() &&
+ info()->opt_count() == id) {
__ Jump(entry, RelocInfo::RUNTIME_ENTRY);
return;
}
@@ -1209,8 +1210,6 @@
Label vfp_modulo, both_positive, right_negative;
- CpuFeatureScope scope(masm(), VFP2);
-
// Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
__ cmp(right, Operand::Zero());
@@ -1615,7 +1614,6 @@
LOperand* left_argument,
LOperand* right_argument,
Token::Value op) {
- CpuFeatureScope vfp_scope(masm(), VFP2);
Register left = ToRegister(left_argument);
Register right = ToRegister(right_argument);
@@ -1901,7 +1899,6 @@
void LCodeGen::DoConstantD(LConstantD* instr) {
ASSERT(instr->result()->IsDoubleRegister());
DwVfpRegister result = ToDoubleRegister(instr->result());
- CpuFeatureScope scope(masm(), VFP2);
double v = instr->value();
__ Vmov(result, v, scratch0());
}
@@ -2072,7 +2069,6 @@
__ mov(result_reg, right_op, LeaveCC, NegateCondition(condition));
} else {
ASSERT(instr->hydrogen()->representation().IsDouble());
- CpuFeatureScope scope(masm(), VFP2);
DwVfpRegister left_reg = ToDoubleRegister(left);
DwVfpRegister right_reg = ToDoubleRegister(right);
DwVfpRegister result_reg = ToDoubleRegister(instr->result());
@@ -2118,7 +2114,6 @@
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
- CpuFeatureScope scope(masm(), VFP2);
DwVfpRegister left = ToDoubleRegister(instr->left());
DwVfpRegister right = ToDoubleRegister(instr->right());
DwVfpRegister result = ToDoubleRegister(instr->result());
@@ -2209,7 +2204,6 @@
__ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
} else if (r.IsDouble()) {
- CpuFeatureScope scope(masm(), VFP2);
DwVfpRegister reg = ToDoubleRegister(instr->value());
Register scratch = scratch0();
@@ -2301,7 +2295,6 @@
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
- CpuFeatureScope scope(masm(), VFP2);
// heap number -> false iff +0, -0, or NaN.
DwVfpRegister dbl_scratch = double_scratch0();
Label not_heap_number;
@@ -2381,7 +2374,6 @@
EmitGoto(next_block);
} else {
if (instr->is_double()) {
- CpuFeatureScope scope(masm(), VFP2);
// Compare left and right operands as doubles and load the
// resulting flags into the normal status register.
__ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
@@ -2936,8 +2928,7 @@
__ push(r0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
- if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
+ if (info()->saves_caller_doubles()) {
ASSERT(NeedsEagerFrame());
BitVector* doubles = chunk()->allocated_double_registers();
BitVector::Iterator save_iterator(doubles);
@@ -3319,58 +3310,11 @@
? Operand(constant_key << element_size_shift)
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- __ vldr(kScratchDoubleReg.low(), scratch0(), additional_offset);
- __ vcvt_f64_f32(result, kScratchDoubleReg.low());
- } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
- __ vldr(result, scratch0(), additional_offset);
- }
- } else {
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- Register value = external_pointer;
- __ ldr(value, MemOperand(scratch0(), additional_offset));
- __ and_(sfpd_lo, value, Operand(kBinary32MantissaMask));
-
- __ mov(scratch0(), Operand(value, LSR, kBinary32MantissaBits));
- __ and_(scratch0(), scratch0(),
- Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
-
- Label exponent_rebiased;
- __ teq(scratch0(), Operand(0x00));
- __ b(eq, &exponent_rebiased);
-
- __ teq(scratch0(), Operand(0xff));
- __ mov(scratch0(), Operand(0x7ff), LeaveCC, eq);
- __ b(eq, &exponent_rebiased);
-
- // Rebias exponent.
- __ add(scratch0(),
- scratch0(),
- Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
-
- __ bind(&exponent_rebiased);
- __ and_(sfpd_hi, value, Operand(kBinary32SignMask));
- __ orr(sfpd_hi, sfpd_hi,
- Operand(scratch0(), LSL, HeapNumber::kMantissaBitsInTopWord));
-
- // Shift mantissa.
- static const int kMantissaShiftForHiWord =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaShiftForLoWord =
- kBitsPerInt - kMantissaShiftForHiWord;
-
- __ orr(sfpd_hi, sfpd_hi,
- Operand(sfpd_lo, LSR, kMantissaShiftForHiWord));
- __ mov(sfpd_lo, Operand(sfpd_lo, LSL, kMantissaShiftForLoWord));
-
- } else {
- __ ldr(sfpd_lo, MemOperand(scratch0(), additional_offset));
- __ ldr(sfpd_hi, MemOperand(scratch0(),
- additional_offset + kPointerSize));
- }
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ __ vldr(kScratchDoubleReg.low(), scratch0(), additional_offset);
+ __ vcvt_f64_f32(result, kScratchDoubleReg.low());
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
+ __ vldr(result, scratch0(), additional_offset);
}
} else {
Register result = ToRegister(instr->result());
@@ -3444,23 +3388,12 @@
if (!key_is_constant) {
__ add(elements, elements, Operand(key, LSL, shift_size));
}
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- __ add(elements, elements, Operand(base_offset));
- __ vldr(result, elements, 0);
- if (instr->hydrogen()->RequiresHoleCheck()) {
- __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
- __ cmp(scratch, Operand(kHoleNanUpper32));
- DeoptimizeIf(eq, instr->environment());
- }
- } else {
- __ ldr(sfpd_hi, MemOperand(elements, base_offset + kPointerSize));
- __ ldr(sfpd_lo, MemOperand(elements, base_offset));
- if (instr->hydrogen()->RequiresHoleCheck()) {
- ASSERT(kPointerSize == sizeof(kHoleNanLower32));
- __ cmp(sfpd_hi, Operand(kHoleNanUpper32));
- DeoptimizeIf(eq, instr->environment());
- }
+ __ add(elements, elements, Operand(base_offset));
+ __ vldr(result, elements, 0);
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+ __ cmp(scratch, Operand(kHoleNanUpper32));
+ DeoptimizeIf(eq, instr->environment());
}
}
@@ -3821,7 +3754,7 @@
}
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
@@ -3887,7 +3820,7 @@
}
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
__ cmp(input, Operand::Zero());
@@ -3901,20 +3834,18 @@
}
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
// Class for deferred case.
class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
public:
- DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
- LUnaryMathOperation* instr)
+ DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
}
virtual LInstruction* instr() { return instr_; }
private:
- LUnaryMathOperation* instr_;
+ LMathAbs* instr_;
};
Representation r = instr->hydrogen()->value()->representation();
@@ -3938,8 +3869,7 @@
}
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
DwVfpRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
Register input_high = scratch0();
@@ -3961,8 +3891,7 @@
}
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathRound(LMathRound* instr) {
DwVfpRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp());
@@ -4001,16 +3930,14 @@
}
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
DwVfpRegister input = ToDoubleRegister(instr->value());
DwVfpRegister result = ToDoubleRegister(instr->result());
__ vsqrt(result, input);
}
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
DwVfpRegister input = ToDoubleRegister(instr->value());
DwVfpRegister result = ToDoubleRegister(instr->result());
DwVfpRegister temp = ToDoubleRegister(instr->temp());
@@ -4032,7 +3959,6 @@
void LCodeGen::DoPower(LPower* instr) {
- CpuFeatureScope scope(masm(), VFP2);
Representation exponent_type = instr->hydrogen()->right()->representation();
// Having marked this as a call, we can use any registers.
// Just make sure that the input/output registers are the expected ones.
@@ -4065,7 +3991,6 @@
void LCodeGen::DoRandom(LRandom* instr) {
- CpuFeatureScope scope(masm(), VFP2);
class DeferredDoRandom: public LDeferredCode {
public:
DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
@@ -4144,7 +4069,6 @@
void LCodeGen::DoMathExp(LMathExp* instr) {
- CpuFeatureScope scope(masm(), VFP2);
DwVfpRegister input = ToDoubleRegister(instr->value());
DwVfpRegister result = ToDoubleRegister(instr->result());
DwVfpRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
@@ -4158,7 +4082,7 @@
}
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::UNTAGGED);
@@ -4166,7 +4090,7 @@
}
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
TranscendentalCacheStub stub(TranscendentalCache::TAN,
TranscendentalCacheStub::UNTAGGED);
@@ -4174,7 +4098,7 @@
}
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
@@ -4182,7 +4106,7 @@
}
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
@@ -4190,42 +4114,6 @@
}
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
- switch (instr->op()) {
- case kMathAbs:
- DoMathAbs(instr);
- break;
- case kMathFloor:
- DoMathFloor(instr);
- break;
- case kMathRound:
- DoMathRound(instr);
- break;
- case kMathSqrt:
- DoMathSqrt(instr);
- break;
- case kMathPowHalf:
- DoMathPowHalf(instr);
- break;
- case kMathCos:
- DoMathCos(instr);
- break;
- case kMathSin:
- DoMathSin(instr);
- break;
- case kMathTan:
- DoMathTan(instr);
- break;
- case kMathLog:
- DoMathLog(instr);
- break;
- default:
- Abort("Unimplemented type of LUnaryMathOperation.");
- UNREACHABLE();
- }
-}
-
-
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(instr->HasPointerMap());
@@ -4442,7 +4330,6 @@
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
- CpuFeatureScope scope(masm(), VFP2);
Register external_pointer = ToRegister(instr->elements());
Register key = no_reg;
ElementsKind elements_kind = instr->elements_kind();
@@ -4463,7 +4350,6 @@
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- CpuFeatureScope scope(masm(), VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
Operand operand(key_is_constant
? Operand(constant_key << element_size_shift)
@@ -4513,7 +4399,6 @@
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
- CpuFeatureScope scope(masm(), VFP2);
DwVfpRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Register key = no_reg;
@@ -4545,18 +4430,14 @@
}
if (instr->NeedsCanonicalization()) {
- // Check for NaN. All NaNs must be canonicalized.
- __ VFPCompareAndSetFlags(value, value);
- Label after_canonicalization;
-
- // Only load canonical NaN if the comparison above set the overflow.
- __ b(vc, &after_canonicalization);
- __ Vmov(value,
- FixedDoubleArray::canonical_not_the_hole_nan_as_double());
-
- __ bind(&after_canonicalization);
+ // Force a canonical NaN.
+ if (masm()->emit_debug_code()) {
+ __ vmrs(ip);
+ __ tst(ip, Operand(kVFPDefaultNaNModeControlBit));
+ __ Assert(ne, "Default NaN mode not set");
+ }
+ __ VFPCanonicalizeNaN(value);
}
-
__ vstr(value, scratch, instr->additional_index() << element_size_shift);
}
@@ -4814,7 +4695,6 @@
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
- CpuFeatureScope scope(masm(), VFP2);
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
LOperand* output = instr->result();
@@ -4832,7 +4712,6 @@
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
- CpuFeatureScope scope(masm(), VFP2);
LOperand* input = instr->value();
LOperand* output = instr->result();
@@ -4894,43 +4773,6 @@
}
-// Convert unsigned integer with specified number of leading zeroes in binary
-// representation to IEEE 754 double.
-// Integer to convert is passed in register src.
-// Resulting double is returned in registers hiword:loword.
-// This functions does not work correctly for 0.
-static void GenerateUInt2Double(MacroAssembler* masm,
- Register src,
- Register hiword,
- Register loword,
- Register scratch,
- int leading_zeroes) {
- const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
- const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
-
- const int mantissa_shift_for_hi_word =
- meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
- const int mantissa_shift_for_lo_word =
- kBitsPerInt - mantissa_shift_for_hi_word;
- masm->mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
- if (mantissa_shift_for_hi_word > 0) {
- masm->mov(loword, Operand(src, LSL, mantissa_shift_for_lo_word));
- masm->orr(hiword, scratch,
- Operand(src, LSR, mantissa_shift_for_hi_word));
- } else {
- masm->mov(loword, Operand::Zero());
- masm->orr(hiword, scratch,
- Operand(src, LSL, -mantissa_shift_for_hi_word));
- }
-
- // If least significant bit of biased exponent was not 1 it was corrupted
- // by most significant bit of mantissa so we should fix that.
- if (!(biased_exponent & 1)) {
- masm->bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift));
- }
-}
-
-
void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
LOperand* value,
IntegerSignedness signedness) {
@@ -4952,35 +4794,11 @@
__ SmiUntag(src, dst);
__ eor(src, src, Operand(0x80000000));
}
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- __ vmov(flt_scratch, src);
- __ vcvt_f64_s32(dbl_scratch, flt_scratch);
- } else {
- FloatingPointHelper::Destination dest =
- FloatingPointHelper::kCoreRegisters;
- FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, d0,
- sfpd_lo, sfpd_hi,
- scratch0(), s0);
- }
+ __ vmov(flt_scratch, src);
+ __ vcvt_f64_s32(dbl_scratch, flt_scratch);
} else {
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- __ vmov(flt_scratch, src);
- __ vcvt_f64_u32(dbl_scratch, flt_scratch);
- } else {
- Label no_leading_zero, convert_done;
- __ tst(src, Operand(0x80000000));
- __ b(ne, &no_leading_zero);
-
- // Integer has one leading zeros.
- GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 1);
- __ b(&convert_done);
-
- __ bind(&no_leading_zero);
- GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 0);
- __ bind(&convert_done);
- }
+ __ vmov(flt_scratch, src);
+ __ vcvt_f64_u32(dbl_scratch, flt_scratch);
}
if (FLAG_inline_new) {
@@ -4996,30 +4814,16 @@
// TODO(3095996): Put a valid pointer value in the stack slot where the result
// register is stored, as this register is in the pointer map, but contains an
// integer value.
- if (!CpuFeatures::IsSupported(VFP2)) {
- // Preserve sfpd_lo.
- __ mov(r9, sfpd_lo);
- }
__ mov(ip, Operand::Zero());
__ StoreToSafepointRegisterSlot(ip, dst);
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
__ Move(dst, r0);
- if (!CpuFeatures::IsSupported(VFP2)) {
- // Restore sfpd_lo.
- __ mov(sfpd_lo, r9);
- }
__ sub(dst, dst, Operand(kHeapObjectTag));
// Done. Put the value in dbl_scratch into the value of the allocated heap
// number.
__ bind(&done);
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset);
- } else {
- __ str(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset));
- __ str(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset));
- }
+ __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset);
__ add(dst, dst, Operand(kHeapObjectTag));
__ StoreToSafepointRegisterSlot(dst, dst);
}
@@ -5052,45 +4856,16 @@
Label no_special_nan_handling;
Label done;
if (convert_hole) {
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- DwVfpRegister input_reg = ToDoubleRegister(instr->value());
- __ VFPCompareAndSetFlags(input_reg, input_reg);
- __ b(vc, &no_special_nan_handling);
- __ vmov(reg, scratch0(), input_reg);
- __ cmp(scratch0(), Operand(kHoleNanUpper32));
- Label canonicalize;
- __ b(ne, &canonicalize);
- __ Move(reg, factory()->the_hole_value());
- __ b(&done);
- __ bind(&canonicalize);
- __ Vmov(input_reg,
- FixedDoubleArray::canonical_not_the_hole_nan_as_double(),
- no_reg);
- } else {
- Label not_hole;
- __ cmp(sfpd_hi, Operand(kHoleNanUpper32));
- __ b(ne, ¬_hole);
- __ Move(reg, factory()->the_hole_value());
- __ b(&done);
- __ bind(¬_hole);
- __ and_(scratch, sfpd_hi, Operand(0x7ff00000));
- __ cmp(scratch, Operand(0x7ff00000));
- __ b(ne, &no_special_nan_handling);
- Label special_nan_handling;
- __ tst(sfpd_hi, Operand(0x000FFFFF));
- __ b(ne, &special_nan_handling);
- __ cmp(sfpd_lo, Operand(0));
- __ b(eq, &no_special_nan_handling);
- __ bind(&special_nan_handling);
- double canonical_nan =
- FixedDoubleArray::canonical_not_the_hole_nan_as_double();
- uint64_t casted_nan = BitCast<uint64_t>(canonical_nan);
- __ mov(sfpd_lo,
- Operand(static_cast<uint32_t>(casted_nan & 0xFFFFFFFF)));
- __ mov(sfpd_hi,
- Operand(static_cast<uint32_t>(casted_nan >> 32)));
- }
+ DwVfpRegister input_reg = ToDoubleRegister(instr->value());
+ __ VFPCompareAndSetFlags(input_reg, input_reg);
+ __ b(vc, &no_special_nan_handling);
+ __ vmov(scratch, input_reg.high());
+ __ cmp(scratch, Operand(kHoleNanUpper32));
+ // If not the hole NaN, force the NaN to be canonical.
+ __ VFPCanonicalizeNaN(input_reg, ne);
+ __ b(ne, &no_special_nan_handling);
+ __ Move(reg, factory()->the_hole_value());
+ __ b(&done);
}
__ bind(&no_special_nan_handling);
@@ -5104,13 +4879,7 @@
__ jmp(deferred->entry());
}
__ bind(deferred->exit());
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm(), VFP2);
- __ vstr(input_reg, reg, HeapNumber::kValueOffset);
- } else {
- __ str(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset));
- __ str(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize));
- }
+ __ vstr(input_reg, reg, HeapNumber::kValueOffset);
// Now that we have finished with the object's real address tag it
__ add(reg, reg, Operand(kHeapObjectTag));
__ bind(&done);
@@ -5160,7 +4929,6 @@
Register scratch = scratch0();
SwVfpRegister flt_scratch = double_scratch0().low();
ASSERT(!result_reg.is(double_scratch0()));
- CpuFeatureScope scope(masm(), VFP2);
Label load_smi, heap_number, done;
@@ -5249,7 +5017,6 @@
__ cmp(scratch1, Operand(ip));
if (instr->truncating()) {
- CpuFeatureScope scope(masm(), VFP2);
Register scratch3 = ToRegister(instr->temp2());
ASSERT(!scratch3.is(input_reg) &&
!scratch3.is(scratch1) &&
@@ -5270,11 +5037,10 @@
__ sub(scratch1, input_reg, Operand(kHeapObjectTag));
__ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
- __ ECMAToInt32VFP(input_reg, double_scratch2, double_scratch,
- scratch1, scratch2, scratch3);
+ __ ECMAToInt32(input_reg, double_scratch2, double_scratch,
+ scratch1, scratch2, scratch3);
} else {
- CpuFeatureScope scope(masm(), VFP3);
// Deoptimize if we don't have a heap number.
DeoptimizeIf(ne, instr->environment());
@@ -5369,8 +5135,8 @@
if (instr->truncating()) {
Register scratch3 = ToRegister(instr->temp2());
- __ ECMAToInt32VFP(result_reg, double_input, double_scratch,
- scratch1, scratch2, scratch3);
+ __ ECMAToInt32(result_reg, double_input, double_scratch,
+ scratch1, scratch2, scratch3);
} else {
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
// Deoptimize if the input wasn't a int32 (inside a double).
@@ -5486,7 +5252,6 @@
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
- CpuFeatureScope vfp_scope(masm(), VFP2);
DwVfpRegister value_reg = ToDoubleRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
DwVfpRegister temp_reg = ToDoubleRegister(instr->temp());
@@ -5495,7 +5260,6 @@
void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
- CpuFeatureScope scope(masm(), VFP2);
Register unclamped_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
__ ClampUint8(result_reg, unclamped_reg);
@@ -5503,7 +5267,6 @@
void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
- CpuFeatureScope scope(masm(), VFP2);
Register scratch = scratch0();
Register input_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
@@ -5541,7 +5304,6 @@
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
- ASSERT(instr->temp()->Equals(instr->result()));
Register prototype_reg = ToRegister(instr->temp());
Register map_reg = ToRegister(instr->temp2());
@@ -5554,8 +5316,6 @@
for (int i = 0; i < maps->length(); i++) {
prototype_maps_.Add(maps->at(i), info()->zone());
}
- __ LoadHeapObject(prototype_reg,
- prototypes->at(prototypes->length() - 1));
} else {
for (int i = 0; i < prototypes->length(); i++) {
__ LoadHeapObject(prototype_reg, prototypes->at(i));
@@ -5671,11 +5431,11 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+ }
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- }
__ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
@@ -5703,7 +5463,13 @@
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ SmiTag(size, size);
__ push(size);
- CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInOldPointerSpace, 1, instr);
+ } else {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInNewSpace, 1, instr);
+ }
__ StoreToSafepointRegisterSlot(r0, result);
}
@@ -5737,7 +5503,6 @@
// Boilerplate already exists, constant elements are never accessed.
// Pass an empty fixed array.
__ mov(r1, Operand(isolate()->factory()->empty_fixed_array()));
- __ Push(r3, r2, r1);
// Pick the right runtime function or stub to call.
int length = instr->hydrogen()->length();
@@ -5748,8 +5513,10 @@
FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else if (instr->hydrogen()->depth() > 1) {
+ __ Push(r3, r2, r1);
CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ Push(r3, r2, r1);
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
} else {
FastCloneShallowArrayStub::Mode mode =
@@ -5762,170 +5529,6 @@
}
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
- Register result,
- Register source,
- int* offset,
- AllocationSiteMode mode) {
- ASSERT(!source.is(r2));
- ASSERT(!result.is(r2));
-
- bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
- object->map()->CanTrackAllocationSite();
-
- // Only elements backing stores for non-COW arrays need to be copied.
- Handle<FixedArrayBase> elements(object->elements());
- bool has_elements = elements->length() > 0 &&
- elements->map() != isolate()->heap()->fixed_cow_array_map();
-
- // Increase the offset so that subsequent objects end up right after
- // this object and its backing store.
- int object_offset = *offset;
- int object_size = object->map()->instance_size();
- int elements_size = has_elements ? elements->Size() : 0;
- int elements_offset = *offset + object_size;
- if (create_allocation_site_info) {
- elements_offset += AllocationSiteInfo::kSize;
- *offset += AllocationSiteInfo::kSize;
- }
-
- *offset += object_size + elements_size;
-
- // Copy object header.
- ASSERT(object->properties()->length() == 0);
- int inobject_properties = object->map()->inobject_properties();
- int header_size = object_size - inobject_properties * kPointerSize;
- for (int i = 0; i < header_size; i += kPointerSize) {
- if (has_elements && i == JSObject::kElementsOffset) {
- __ add(r2, result, Operand(elements_offset));
- } else {
- __ ldr(r2, FieldMemOperand(source, i));
- }
- __ str(r2, FieldMemOperand(result, object_offset + i));
- }
-
- // Copy in-object properties.
- for (int i = 0; i < inobject_properties; i++) {
- int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
- Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
- isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ add(r2, result, Operand(*offset));
- __ str(r2, FieldMemOperand(result, total_offset));
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(r2, Handle<HeapObject>::cast(value));
- __ str(r2, FieldMemOperand(result, total_offset));
- } else {
- __ mov(r2, Operand(value));
- __ str(r2, FieldMemOperand(result, total_offset));
- }
- }
-
- // Build Allocation Site Info if desired
- if (create_allocation_site_info) {
- __ mov(r2, Operand(Handle<Map>(isolate()->heap()->
- allocation_site_info_map())));
- __ str(r2, FieldMemOperand(result, object_size));
- __ str(source, FieldMemOperand(result, object_size + kPointerSize));
- }
-
- if (has_elements) {
- // Copy elements backing store header.
- __ LoadHeapObject(source, elements);
- for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
- __ ldr(r2, FieldMemOperand(source, i));
- __ str(r2, FieldMemOperand(result, elements_offset + i));
- }
-
- // Copy elements backing store content.
- int elements_length = has_elements ? elements->length() : 0;
- if (elements->IsFixedDoubleArray()) {
- Handle<FixedDoubleArray> double_array =
- Handle<FixedDoubleArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int64_t value = double_array->get_representation(i);
- // We only support little endian mode...
- int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
- int32_t value_high = static_cast<int32_t>(value >> 32);
- int total_offset =
- elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
- __ mov(r2, Operand(value_low));
- __ str(r2, FieldMemOperand(result, total_offset));
- __ mov(r2, Operand(value_high));
- __ str(r2, FieldMemOperand(result, total_offset + 4));
- }
- } else if (elements->IsFixedArray()) {
- Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value(fast_elements->get(i), isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ add(r2, result, Operand(*offset));
- __ str(r2, FieldMemOperand(result, total_offset));
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(r2, Handle<HeapObject>::cast(value));
- __ str(r2, FieldMemOperand(result, total_offset));
- } else {
- __ mov(r2, Operand(value));
- __ str(r2, FieldMemOperand(result, total_offset));
- }
- }
- } else {
- UNREACHABLE();
- }
- }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
- int size = instr->hydrogen()->total_size();
- ElementsKind boilerplate_elements_kind =
- instr->hydrogen()->boilerplate()->GetElementsKind();
-
- // Deopt if the array literal boilerplate ElementsKind is of a type different
- // than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
- if (CanTransitionToMoreGeneralFastElementsKind(
- boilerplate_elements_kind, true)) {
- __ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
- // Load map into r2.
- __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
- // Load the map's "bit field 2".
- __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
- // Retrieve elements_kind from bit field 2.
- __ ubfx(r2, r2, Map::kElementsKindShift, Map::kElementsKindBitCount);
- __ cmp(r2, Operand(boilerplate_elements_kind));
- DeoptimizeIf(ne, instr->environment());
- }
-
- // Allocate all objects that are part of the literal in one big
- // allocation. This avoids multiple limit checks.
- Label allocated, runtime_allocate;
- __ Allocate(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
- __ jmp(&allocated);
-
- __ bind(&runtime_allocate);
- __ mov(r0, Operand(Smi::FromInt(size)));
- __ push(r0);
- CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
- __ bind(&allocated);
- int offset = 0;
- __ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
- EmitDeepCopy(instr->hydrogen()->boilerplate(), r0, r1, &offset,
- instr->hydrogen()->allocation_site_mode());
- ASSERT_EQ(size, offset);
-}
-
-
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
Handle<FixedArray> literals(instr->environment()->closure()->literals());
Handle<FixedArray> constant_properties =
@@ -6002,17 +5605,8 @@
__ bind(&allocated);
// Copy the content into the newly allocated memory.
- // (Unroll copy loop once for better throughput).
- for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
- __ ldr(r3, FieldMemOperand(r1, i));
- __ ldr(r2, FieldMemOperand(r1, i + kPointerSize));
- __ str(r3, FieldMemOperand(r0, i));
- __ str(r2, FieldMemOperand(r0, i + kPointerSize));
- }
- if ((size % (2 * kPointerSize)) != 0) {
- __ ldr(r3, FieldMemOperand(r1, size - kPointerSize));
- __ str(r3, FieldMemOperand(r0, size - kPointerSize));
- }
+ __ CopyFields(r0, r1, double_scratch0(), double_scratch0().low(),
+ size / kPointerSize);
}
@@ -6022,7 +5616,8 @@
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode());
+ FastNewClosureStub stub(shared_info->language_mode(),
+ shared_info->is_generator());
__ mov(r1, Operand(shared_info));
__ push(r1);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 686241d..3e24dae 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -137,7 +137,7 @@
IntegerSignedness signedness);
void DoDeferredTaggedToI(LTaggedToI* instr);
- void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+ void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -294,17 +294,7 @@
Register ToRegister(int index) const;
DwVfpRegister ToDoubleRegister(int index) const;
- // Specific math operations - used from DoUnaryMathOperation.
- void EmitIntegerMathAbs(LUnaryMathOperation* instr);
- void DoMathAbs(LUnaryMathOperation* instr);
- void DoMathFloor(LUnaryMathOperation* instr);
- void DoMathRound(LUnaryMathOperation* instr);
- void DoMathSqrt(LUnaryMathOperation* instr);
- void DoMathPowHalf(LUnaryMathOperation* instr);
- void DoMathLog(LUnaryMathOperation* instr);
- void DoMathTan(LUnaryMathOperation* instr);
- void DoMathCos(LUnaryMathOperation* instr);
- void DoMathSin(LUnaryMathOperation* instr);
+ void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers,
diff --git a/src/arm/lithium-gap-resolver-arm.cc b/src/arm/lithium-gap-resolver-arm.cc
index a65ab7e..596d58f 100644
--- a/src/arm/lithium-gap-resolver-arm.cc
+++ b/src/arm/lithium-gap-resolver-arm.cc
@@ -171,10 +171,8 @@
} else if (source->IsStackSlot()) {
__ ldr(kSavedValueRegister, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
__ vmov(kScratchDoubleReg, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
__ vldr(kScratchDoubleReg, cgen_->ToMemOperand(source));
} else {
UNREACHABLE();
@@ -194,10 +192,8 @@
} else if (saved_destination_->IsStackSlot()) {
__ str(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
__ vmov(cgen_->ToDoubleRegister(saved_destination_), kScratchDoubleReg);
} else if (saved_destination_->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
__ vstr(kScratchDoubleReg, cgen_->ToMemOperand(saved_destination_));
} else {
UNREACHABLE();
@@ -233,8 +229,7 @@
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
if (!destination_operand.OffsetIsUint12Encodable()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
- // ip is overwritten while saving the value to the destination.
+ // ip is overwritten while saving the value to the destination.
// Therefore we can't use ip. It is OK if the read from the source
// destroys ip, since that happens before the value is read.
__ vldr(kScratchDoubleReg.low(), source_operand);
@@ -272,7 +267,6 @@
}
} else if (source->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
DwVfpRegister source_register = cgen_->ToDoubleRegister(source);
if (destination->IsDoubleRegister()) {
__ vmov(cgen_->ToDoubleRegister(destination), source_register);
@@ -282,8 +276,7 @@
}
} else if (source->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), VFP2);
- MemOperand source_operand = cgen_->ToMemOperand(source);
+ MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsDoubleRegister()) {
__ vldr(cgen_->ToDoubleRegister(destination), source_operand);
} else {
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index bacf570..7df0c0a 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -291,8 +291,6 @@
void MacroAssembler::Move(DwVfpRegister dst, DwVfpRegister src) {
- ASSERT(CpuFeatures::IsSupported(VFP2));
- CpuFeatureScope scope(this, VFP2);
if (!dst.is(src)) {
vmov(dst, src);
}
@@ -775,6 +773,23 @@
}
+void MacroAssembler::VFPEnsureFPSCRState(Register scratch) {
+ // If needed, restore wanted bits of FPSCR.
+ Label fpscr_done;
+ vmrs(scratch);
+ tst(scratch, Operand(kVFPDefaultNaNModeControlBit));
+ b(ne, &fpscr_done);
+ orr(scratch, scratch, Operand(kVFPDefaultNaNModeControlBit));
+ vmsr(scratch);
+ bind(&fpscr_done);
+}
+
+void MacroAssembler::VFPCanonicalizeNaN(const DwVfpRegister value,
+ const Condition cond) {
+ vsub(value, value, kDoubleRegZero, cond);
+}
+
+
void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
const DwVfpRegister src2,
const Condition cond) {
@@ -811,7 +826,6 @@
void MacroAssembler::Vmov(const DwVfpRegister dst,
const double imm,
const Register scratch) {
- ASSERT(IsEnabled(VFP2));
static const DoubleRepresentation minus_zero(-0.0);
static const DoubleRepresentation zero(0.0);
DoubleRepresentation value(imm);
@@ -873,7 +887,6 @@
// Optionally save all double registers.
if (save_doubles) {
- CpuFeatureScope scope(this, VFP2);
// Check CPU flags for number of registers, setting the Z condition flag.
CheckFor32DRegs(ip);
@@ -938,7 +951,6 @@
Register argument_count) {
// Optionally restore all double registers.
if (save_doubles) {
- CpuFeatureScope scope(this, VFP2);
// Calculate the stack location of the saved doubles and restore them.
const int offset = 2 * kPointerSize;
sub(r3, fp,
@@ -975,7 +987,6 @@
}
void MacroAssembler::GetCFunctionDoubleResult(const DwVfpRegister dst) {
- ASSERT(CpuFeatures::IsSupported(VFP2));
if (use_eabi_hardfloat()) {
Move(dst, d0);
} else {
@@ -1402,7 +1413,6 @@
// Check the context is a native context.
if (emit_debug_code()) {
- // TODO(119): avoid push(holder_reg)/pop(holder_reg)
// Cannot use ip as a temporary in this verification code. Due to the fact
// that ip is clobbered as part of cmp with an object Operand.
push(holder_reg); // Temporarily save holder on the stack.
@@ -1421,7 +1431,6 @@
// Check the context is a native context.
if (emit_debug_code()) {
- // TODO(119): avoid push(holder_reg)/pop(holder_reg)
// Cannot use ip as a temporary in this verification code. Due to the fact
// that ip is clobbered as part of cmp with an object Operand.
push(holder_reg); // Temporarily save holder on the stack.
@@ -1991,7 +2000,7 @@
Register scratch4,
Label* fail,
int elements_offset) {
- Label smi_value, maybe_nan, have_double_value, is_nan, done;
+ Label smi_value, store;
Register mantissa_reg = scratch2;
Register exponent_reg = scratch3;
@@ -2005,73 +2014,28 @@
fail,
DONT_DO_SMI_CHECK);
- // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
- // in the exponent.
- mov(scratch1, Operand(kNaNOrInfinityLowerBoundUpper32));
- ldr(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
- cmp(exponent_reg, scratch1);
- b(ge, &maybe_nan);
-
- ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
-
- bind(&have_double_value);
- add(scratch1, elements_reg,
- Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
- str(mantissa_reg, FieldMemOperand(
- scratch1, FixedDoubleArray::kHeaderSize - elements_offset));
- uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset +
- sizeof(kHoleNanLower32);
- str(exponent_reg, FieldMemOperand(scratch1, offset));
- jmp(&done);
-
- bind(&maybe_nan);
- // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
- // it's an Infinity, and the non-NaN code path applies.
- b(gt, &is_nan);
- ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
- cmp(mantissa_reg, Operand::Zero());
- b(eq, &have_double_value);
- bind(&is_nan);
- // Load canonical NaN for storing into the double array.
- uint64_t nan_int64 = BitCast<uint64_t>(
- FixedDoubleArray::canonical_not_the_hole_nan_as_double());
- mov(mantissa_reg, Operand(static_cast<uint32_t>(nan_int64)));
- mov(exponent_reg, Operand(static_cast<uint32_t>(nan_int64 >> 32)));
- jmp(&have_double_value);
+ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
+ // Force a canonical NaN.
+ if (emit_debug_code()) {
+ vmrs(ip);
+ tst(ip, Operand(kVFPDefaultNaNModeControlBit));
+ Assert(ne, "Default NaN mode not set");
+ }
+ VFPCanonicalizeNaN(d0);
+ b(&store);
bind(&smi_value);
- add(scratch1, elements_reg,
- Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
- elements_offset));
- add(scratch1, scratch1,
- Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
- // scratch1 is now effective address of the double element
-
- FloatingPointHelper::Destination destination;
- if (CpuFeatures::IsSupported(VFP2)) {
- destination = FloatingPointHelper::kVFPRegisters;
- } else {
- destination = FloatingPointHelper::kCoreRegisters;
- }
-
- Register untagged_value = elements_reg;
+ Register untagged_value = scratch1;
SmiUntag(untagged_value, value_reg);
- FloatingPointHelper::ConvertIntToDouble(this,
- untagged_value,
- destination,
- d0,
- mantissa_reg,
- exponent_reg,
- scratch4,
- s2);
- if (destination == FloatingPointHelper::kVFPRegisters) {
- CpuFeatureScope scope(this, VFP2);
- vstr(d0, scratch1, 0);
- } else {
- str(mantissa_reg, MemOperand(scratch1, 0));
- str(exponent_reg, MemOperand(scratch1, Register::kSizeInBytes));
- }
- bind(&done);
+ FloatingPointHelper::ConvertIntToDouble(
+ this, untagged_value, FloatingPointHelper::kVFPRegisters, d0,
+ mantissa_reg, exponent_reg, scratch4, s2);
+
+ bind(&store);
+ add(scratch1, elements_reg,
+ Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
+ vstr(d0, FieldMemOperand(scratch1,
+ FixedDoubleArray::kHeaderSize - elements_offset));
}
@@ -2425,9 +2389,6 @@
void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input,
DwVfpRegister double_scratch) {
ASSERT(!double_input.is(double_scratch));
- ASSERT(CpuFeatures::IsSupported(VFP2));
- CpuFeatureScope scope(this, VFP2);
-
vcvt_s32_f64(double_scratch.low(), double_input);
vcvt_f64_s32(double_scratch, double_scratch.low());
VFPCompareAndSetFlags(double_input, double_scratch);
@@ -2438,9 +2399,6 @@
DwVfpRegister double_input,
DwVfpRegister double_scratch) {
ASSERT(!double_input.is(double_scratch));
- ASSERT(CpuFeatures::IsSupported(VFP2));
- CpuFeatureScope scope(this, VFP2);
-
vcvt_s32_f64(double_scratch.low(), double_input);
vmov(result, double_scratch.low());
vcvt_f64_s32(double_scratch, double_scratch.low());
@@ -2456,8 +2414,6 @@
Label* exact) {
ASSERT(!result.is(input_high));
ASSERT(!double_input.is(double_scratch));
- ASSERT(CpuFeatures::IsSupported(VFP2));
- CpuFeatureScope scope(this, VFP2);
Label negative, exception;
// Test for NaN and infinities.
@@ -2502,26 +2458,18 @@
Register scratch,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2) {
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(this, VFP2);
- vldr(double_scratch1, FieldMemOperand(source, HeapNumber::kValueOffset));
- ECMAToInt32VFP(result, double_scratch1, double_scratch2,
- scratch, input_high, input_low);
- } else {
- Ldrd(input_low, input_high,
- FieldMemOperand(source, HeapNumber::kValueOffset));
- ECMAToInt32NoVFP(result, scratch, input_high, input_low);
- }
+ vldr(double_scratch1, FieldMemOperand(source, HeapNumber::kValueOffset));
+ ECMAToInt32(result, double_scratch1, double_scratch2,
+ scratch, input_high, input_low);
}
-void MacroAssembler::ECMAToInt32VFP(Register result,
- DwVfpRegister double_input,
- DwVfpRegister double_scratch,
- Register scratch,
- Register input_high,
- Register input_low) {
- CpuFeatureScope scope(this, VFP2);
+void MacroAssembler::ECMAToInt32(Register result,
+ DwVfpRegister double_input,
+ DwVfpRegister double_scratch,
+ Register scratch,
+ Register input_high,
+ Register input_low) {
ASSERT(!input_high.is(result));
ASSERT(!input_low.is(result));
ASSERT(!input_low.is(input_high));
@@ -2561,58 +2509,6 @@
}
-void MacroAssembler::ECMAToInt32NoVFP(Register result,
- Register scratch,
- Register input_high,
- Register input_low) {
- ASSERT(!result.is(scratch));
- ASSERT(!result.is(input_high));
- ASSERT(!result.is(input_low));
- ASSERT(!scratch.is(input_high));
- ASSERT(!scratch.is(input_low));
- ASSERT(!input_high.is(input_low));
-
- Label both, out_of_range, negate, done;
-
- Ubfx(scratch, input_high,
- HeapNumber::kExponentShift, HeapNumber::kExponentBits);
- // Load scratch with exponent.
- sub(scratch, scratch, Operand(HeapNumber::kExponentBias));
- // If exponent is negative, 0 < input < 1, the result is 0.
- // If exponent is greater than or equal to 84, the 32 less significant
- // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
- // the result is 0.
- // This test also catch Nan and infinities which also return 0.
- cmp(scratch, Operand(84));
- // We do an unsigned comparison so negative numbers are treated as big
- // positive number and the two tests above are done in one test.
- b(hs, &out_of_range);
-
- // Load scratch with 20 - exponent.
- rsb(scratch, scratch, Operand(20), SetCC);
- b(mi, &both);
-
- // Test 0 and -0.
- bic(result, input_high, Operand(HeapNumber::kSignMask));
- orr(result, result, Operand(input_low), SetCC);
- b(eq, &done);
- // 0 <= exponent <= 20, shift only input_high.
- // Scratch contains: 20 - exponent.
- Ubfx(result, input_high,
- 0, HeapNumber::kMantissaBitsInTopWord);
- // Set the implicit 1 before the mantissa part in input_high.
- orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord));
- mov(result, Operand(result, LSR, scratch));
- b(&negate);
-
- bind(&both);
- // Restore scratch to exponent - 1 to be consistent with ECMAToInt32VFP.
- rsb(scratch, scratch, Operand(19));
- ECMAToInt32Tail(result, scratch, input_high, input_low,
- &out_of_range, &negate, &done);
-}
-
-
void MacroAssembler::ECMAToInt32Tail(Register result,
Register scratch,
Register input_high,
@@ -2715,10 +2611,7 @@
const Runtime::Function* function = Runtime::FunctionForId(id);
mov(r0, Operand(function->nargs));
mov(r1, Operand(ExternalReference(function, isolate())));
- SaveFPRegsMode mode = CpuFeatures::IsSupported(VFP2)
- ? kSaveFPRegs
- : kDontSaveFPRegs;
- CEntryStub stub(1, mode);
+ CEntryStub stub(1, kSaveFPRegs);
CallStub(&stub);
}
@@ -3244,27 +3137,24 @@
// Copies a fixed number of fields of heap objects from src to dst.
void MacroAssembler::CopyFields(Register dst,
Register src,
- RegList temps,
+ DwVfpRegister double_scratch,
+ SwVfpRegister single_scratch,
int field_count) {
- // At least one bit set in the first 15 registers.
- ASSERT((temps & ((1 << 15) - 1)) != 0);
- ASSERT((temps & dst.bit()) == 0);
- ASSERT((temps & src.bit()) == 0);
- // Primitive implementation using only one temporary register.
-
- Register tmp = no_reg;
- // Find a temp register in temps list.
- for (int i = 0; i < 15; i++) {
- if ((temps & (1 << i)) != 0) {
- tmp.set_code(i);
- break;
- }
+ int double_count = field_count / (DwVfpRegister::kSizeInBytes / kPointerSize);
+ for (int i = 0; i < double_count; i++) {
+ vldr(double_scratch, FieldMemOperand(src, i * DwVfpRegister::kSizeInBytes));
+ vstr(double_scratch, FieldMemOperand(dst, i * DwVfpRegister::kSizeInBytes));
}
- ASSERT(!tmp.is(no_reg));
- for (int i = 0; i < field_count; i++) {
- ldr(tmp, FieldMemOperand(src, i * kPointerSize));
- str(tmp, FieldMemOperand(dst, i * kPointerSize));
+ STATIC_ASSERT(SwVfpRegister::kSizeInBytes == kPointerSize);
+ STATIC_ASSERT(2 * SwVfpRegister::kSizeInBytes == DwVfpRegister::kSizeInBytes);
+
+ int remain = field_count % (DwVfpRegister::kSizeInBytes / kPointerSize);
+ if (remain != 0) {
+ vldr(single_scratch,
+ FieldMemOperand(src, (field_count - 1) * kPointerSize));
+ vstr(single_scratch,
+ FieldMemOperand(dst, (field_count - 1) * kPointerSize));
}
}
@@ -3463,7 +3353,6 @@
void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg) {
- ASSERT(CpuFeatures::IsSupported(VFP2));
if (use_eabi_hardfloat()) {
Move(d0, dreg);
} else {
@@ -3474,7 +3363,6 @@
void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg1,
DwVfpRegister dreg2) {
- ASSERT(CpuFeatures::IsSupported(VFP2));
if (use_eabi_hardfloat()) {
if (dreg2.is(d0)) {
ASSERT(!dreg1.is(d1));
@@ -3493,7 +3381,6 @@
void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg,
Register reg) {
- ASSERT(CpuFeatures::IsSupported(VFP2));
if (use_eabi_hardfloat()) {
Move(d0, dreg);
Move(r0, reg);
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 958fcac..86ae8f2 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -460,6 +460,19 @@
const MemOperand& dst,
Condition cond = al);
+ // Ensure that FPSCR contains values needed by JavaScript.
+ // We need the NaNModeControlBit to be sure that operations like
+ // vadd and vsub generate the Canonical NaN (if a NaN must be generated).
+ // In VFP3 it will be always the Canonical NaN.
+ // In VFP2 it will be either the Canonical NaN or the negative version
+ // of the Canonical NaN. It doesn't matter if we have two values. The aim
+ // is to be sure to never generate the hole NaN.
+ void VFPEnsureFPSCRState(Register scratch);
+
+ // If the value is a NaN, canonicalize the value else, do nothing.
+ void VFPCanonicalizeNaN(const DwVfpRegister value,
+ const Condition cond = al);
+
// Compare double values and move the result to the normal condition flags.
void VFPCompareAndSetFlags(const DwVfpRegister src1,
const DwVfpRegister src2,
@@ -743,7 +756,11 @@
Label* gc_required);
// Copies a fixed number of fields of heap objects from src to dst.
- void CopyFields(Register dst, Register src, RegList temps, int field_count);
+ void CopyFields(Register dst,
+ Register src,
+ DwVfpRegister double_scratch,
+ SwVfpRegister single_scratch,
+ int field_count);
// Copies a number of bytes from src to dst. All registers are clobbered. On
// exit src and dst will point to the place just after where the last byte was
@@ -969,20 +986,12 @@
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
// Exits with 'result' holding the answer and all other registers clobbered.
- void ECMAToInt32VFP(Register result,
- DwVfpRegister double_input,
- DwVfpRegister double_scratch,
- Register scratch,
- Register input_high,
- Register input_low);
-
- // Performs a truncating conversion of a floating point number as used by
- // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
- // Exits with 'result' holding the answer.
- void ECMAToInt32NoVFP(Register result,
- Register scratch,
- Register input_high,
- Register input_low);
+ void ECMAToInt32(Register result,
+ DwVfpRegister double_input,
+ DwVfpRegister double_scratch,
+ Register scratch,
+ Register input_high,
+ Register input_low);
// Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
// instruction. On pre-ARM5 hardware this routine gives the wrong answer
@@ -1140,7 +1149,9 @@
// EABI variant for double arguments in use.
bool use_eabi_hardfloat() {
-#if USE_EABI_HARDFLOAT
+#ifdef __arm__
+ return OS::ArmUsingHardFloat();
+#elif USE_EABI_HARDFLOAT
return true;
#else
return false;
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index 2551e14..ad4d77d 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -721,7 +721,7 @@
Instruction::kInstrSize) == 0);
} else {
// Cache miss. Load memory into the cache.
- memcpy(cached_line, line, CachePage::kLineLength);
+ OS::MemCopy(cached_line, line, CachePage::kLineLength);
*cache_valid_byte = CachePage::LINE_VALID;
}
}
@@ -773,6 +773,7 @@
c_flag_FPSCR_ = false;
v_flag_FPSCR_ = false;
FPSCR_rounding_mode_ = RZ;
+ FPSCR_default_NaN_mode_ = true;
inv_op_vfp_flag_ = false;
div_zero_vfp_flag_ = false;
@@ -902,8 +903,8 @@
// Read the bits from the unsigned integer register_[] array
// into the double precision floating point value and return it.
char buffer[2 * sizeof(vfp_registers_[0])];
- memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
- memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+ OS::MemCopy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
+ OS::MemCopy(&dm_val, buffer, 2 * sizeof(registers_[0]));
return(dm_val);
}
@@ -953,9 +954,9 @@
if (register_size == 2) ASSERT(reg_index < DwVfpRegister::NumRegisters());
char buffer[register_size * sizeof(vfp_registers_[0])];
- memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
- memcpy(&vfp_registers_[reg_index * register_size], buffer,
- register_size * sizeof(vfp_registers_[0]));
+ OS::MemCopy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
+ OS::MemCopy(&vfp_registers_[reg_index * register_size], buffer,
+ register_size * sizeof(vfp_registers_[0]));
}
@@ -967,64 +968,34 @@
ReturnType value = 0;
char buffer[register_size * sizeof(vfp_registers_[0])];
- memcpy(buffer, &vfp_registers_[register_size * reg_index],
- register_size * sizeof(vfp_registers_[0]));
- memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
+ OS::MemCopy(buffer, &vfp_registers_[register_size * reg_index],
+ register_size * sizeof(vfp_registers_[0]));
+ OS::MemCopy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
return value;
}
-// For use in calls that take two double values, constructed either
+// Runtime FP routines take up to two double arguments and zero
+// or one integer arguments. All are constructed here,
// from r0-r3 or d0 and d1.
-void Simulator::GetFpArgs(double* x, double* y) {
+void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
if (use_eabi_hardfloat()) {
*x = vfp_registers_[0];
*y = vfp_registers_[1];
+ *z = registers_[1];
} else {
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
char buffer[sizeof(*x)];
// Registers 0 and 1 -> x.
- memcpy(buffer, registers_, sizeof(*x));
- memcpy(x, buffer, sizeof(*x));
+ OS::MemCopy(buffer, registers_, sizeof(*x));
+ OS::MemCopy(x, buffer, sizeof(*x));
// Registers 2 and 3 -> y.
- memcpy(buffer, registers_ + 2, sizeof(*y));
- memcpy(y, buffer, sizeof(*y));
- }
-}
-
-// For use in calls that take one double value, constructed either
-// from r0 and r1 or d0.
-void Simulator::GetFpArgs(double* x) {
- if (use_eabi_hardfloat()) {
- *x = vfp_registers_[0];
- } else {
- // We use a char buffer to get around the strict-aliasing rules which
- // otherwise allow the compiler to optimize away the copy.
- char buffer[sizeof(*x)];
- // Registers 0 and 1 -> x.
- memcpy(buffer, registers_, sizeof(*x));
- memcpy(x, buffer, sizeof(*x));
- }
-}
-
-
-// For use in calls that take one double value constructed either
-// from r0 and r1 or d0 and one integer value.
-void Simulator::GetFpArgs(double* x, int32_t* y) {
- if (use_eabi_hardfloat()) {
- *x = vfp_registers_[0];
- *y = registers_[1];
- } else {
- // We use a char buffer to get around the strict-aliasing rules which
- // otherwise allow the compiler to optimize away the copy.
- char buffer[sizeof(*x)];
- // Registers 0 and 1 -> x.
- memcpy(buffer, registers_, sizeof(*x));
- memcpy(x, buffer, sizeof(*x));
- // Register 2 -> y.
- memcpy(buffer, registers_ + 2, sizeof(*y));
- memcpy(y, buffer, sizeof(*y));
+ OS::MemCopy(buffer, registers_ + 2, sizeof(*y));
+ OS::MemCopy(y, buffer, sizeof(*y));
+ // Register 2 -> z.
+ OS::MemCopy(buffer, registers_ + 2, sizeof(*z));
+ OS::MemCopy(z, buffer, sizeof(*z));
}
}
@@ -1033,14 +1004,14 @@
void Simulator::SetFpResult(const double& result) {
if (use_eabi_hardfloat()) {
char buffer[2 * sizeof(vfp_registers_[0])];
- memcpy(buffer, &result, sizeof(buffer));
+ OS::MemCopy(buffer, &result, sizeof(buffer));
// Copy result to d0.
- memcpy(vfp_registers_, buffer, sizeof(buffer));
+ OS::MemCopy(vfp_registers_, buffer, sizeof(buffer));
} else {
char buffer[2 * sizeof(registers_[0])];
- memcpy(buffer, &result, sizeof(buffer));
+ OS::MemCopy(buffer, &result, sizeof(buffer));
// Copy result to r0 and r1.
- memcpy(registers_, buffer, sizeof(buffer));
+ OS::MemCopy(registers_, buffer, sizeof(buffer));
}
}
@@ -1619,12 +1590,12 @@
ReadW(reinterpret_cast<int32_t>(address + 1), instr)
};
double d;
- memcpy(&d, data, 8);
+ OS::MemCopy(&d, data, 8);
set_d_register_from_double(reg, d);
} else {
int32_t data[2];
double d = get_double_from_d_register(reg);
- memcpy(data, &d, 8);
+ OS::MemCopy(data, &d, 8);
WriteW(reinterpret_cast<int32_t>(address), data[0], instr);
WriteW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
}
@@ -1647,10 +1618,12 @@
int32_t arg3,
int32_t arg4,
int32_t arg5);
-typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
- int32_t arg1,
- int32_t arg2,
- int32_t arg3);
+
+// These prototypes handle the four types of FP calls.
+typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPCall)(double darg0);
+typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
@@ -1716,27 +1689,27 @@
intptr_t external =
reinterpret_cast<intptr_t>(redirection->external_function());
if (fp_call) {
+ double dval0, dval1; // one or two double parameters
+ int32_t ival; // zero or one integer parameters
+ int64_t iresult = 0; // integer return value
+ double dresult = 0; // double return value
+ GetFpArgs(&dval0, &dval1, &ival);
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
- SimulatorRuntimeFPCall target =
- reinterpret_cast<SimulatorRuntimeFPCall>(external);
- double dval0, dval1;
- int32_t ival;
+ SimulatorRuntimeCall generic_target =
+ reinterpret_cast<SimulatorRuntimeCall>(external);
switch (redirection->type()) {
case ExternalReference::BUILTIN_FP_FP_CALL:
case ExternalReference::BUILTIN_COMPARE_CALL:
- GetFpArgs(&dval0, &dval1);
PrintF("Call to host function at %p with args %f, %f",
- FUNCTION_ADDR(target), dval0, dval1);
+ FUNCTION_ADDR(generic_target), dval0, dval1);
break;
case ExternalReference::BUILTIN_FP_CALL:
- GetFpArgs(&dval0);
PrintF("Call to host function at %p with arg %f",
- FUNCTION_ADDR(target), dval0);
+ FUNCTION_ADDR(generic_target), dval0);
break;
case ExternalReference::BUILTIN_FP_INT_CALL:
- GetFpArgs(&dval0, &ival);
PrintF("Call to host function at %p with args %f, %d",
- FUNCTION_ADDR(target), dval0, ival);
+ FUNCTION_ADDR(generic_target), dval0, ival);
break;
default:
UNREACHABLE();
@@ -1748,22 +1721,54 @@
PrintF("\n");
}
CHECK(stack_aligned);
- if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
+ switch (redirection->type()) {
+ case ExternalReference::BUILTIN_COMPARE_CALL: {
+ SimulatorRuntimeCompareCall target =
+ reinterpret_cast<SimulatorRuntimeCompareCall>(external);
+ iresult = target(dval0, dval1);
+ set_register(r0, static_cast<int32_t>(iresult));
+ set_register(r1, static_cast<int32_t>(iresult >> 32));
+ break;
+ }
+ case ExternalReference::BUILTIN_FP_FP_CALL: {
+ SimulatorRuntimeFPFPCall target =
+ reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
+ dresult = target(dval0, dval1);
+ SetFpResult(dresult);
+ break;
+ }
+ case ExternalReference::BUILTIN_FP_CALL: {
SimulatorRuntimeFPCall target =
- reinterpret_cast<SimulatorRuntimeFPCall>(external);
- double result = target(arg0, arg1, arg2, arg3);
- SetFpResult(result);
- } else {
- SimulatorRuntimeCall target =
- reinterpret_cast<SimulatorRuntimeCall>(external);
- int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
- int32_t lo_res = static_cast<int32_t>(result);
- int32_t hi_res = static_cast<int32_t>(result >> 32);
- if (::v8::internal::FLAG_trace_sim) {
- PrintF("Returned %08x\n", lo_res);
+ reinterpret_cast<SimulatorRuntimeFPCall>(external);
+ dresult = target(dval0);
+ SetFpResult(dresult);
+ break;
+ }
+ case ExternalReference::BUILTIN_FP_INT_CALL: {
+ SimulatorRuntimeFPIntCall target =
+ reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
+ dresult = target(dval0, ival);
+ SetFpResult(dresult);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+ switch (redirection->type()) {
+ case ExternalReference::BUILTIN_COMPARE_CALL:
+ PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
+ break;
+ case ExternalReference::BUILTIN_FP_FP_CALL:
+ case ExternalReference::BUILTIN_FP_CALL:
+ case ExternalReference::BUILTIN_FP_INT_CALL:
+ PrintF("Returned %f\n", dresult);
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
- set_register(r0, lo_res);
- set_register(r1, hi_res);
}
} else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
SimulatorRuntimeDirectApiCall target =
@@ -1864,6 +1869,11 @@
}
+double Simulator::canonicalizeNaN(double value) {
+ return (FPSCR_default_NaN_mode_ && isnan(value)) ?
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double() : value;
+}
+
// Stop helper functions.
bool Simulator::isStopInstruction(Instruction* instr) {
return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
@@ -2724,11 +2734,13 @@
// vabs
double dm_value = get_double_from_d_register(vm);
double dd_value = fabs(dm_value);
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
} else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
// vneg
double dm_value = get_double_from_d_register(vm);
double dd_value = -dm_value;
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
} else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
@@ -2744,6 +2756,7 @@
// vsqrt
double dm_value = get_double_from_d_register(vm);
double dd_value = sqrt(dm_value);
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
} else if (instr->Opc3Value() == 0x0) {
// vmov immediate.
@@ -2765,12 +2778,14 @@
double dn_value = get_double_from_d_register(vn);
double dm_value = get_double_from_d_register(vm);
double dd_value = dn_value - dm_value;
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
} else {
// vadd
double dn_value = get_double_from_d_register(vn);
double dm_value = get_double_from_d_register(vm);
double dd_value = dn_value + dm_value;
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
}
} else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
@@ -2782,6 +2797,7 @@
double dn_value = get_double_from_d_register(vn);
double dm_value = get_double_from_d_register(vm);
double dd_value = dn_value * dm_value;
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
} else if ((instr->Opc1Value() == 0x0)) {
// vmla, vmls
@@ -2799,9 +2815,13 @@
// result with too high precision.
set_d_register_from_double(vd, dn_val * dm_val);
if (is_vmls) {
- set_d_register_from_double(vd, dd_val - get_double_from_d_register(vd));
+ set_d_register_from_double(
+ vd,
+ canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
} else {
- set_d_register_from_double(vd, dd_val + get_double_from_d_register(vd));
+ set_d_register_from_double(
+ vd,
+ canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
}
} else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
// vdiv
@@ -2813,6 +2833,7 @@
double dm_value = get_double_from_d_register(vm);
double dd_value = dn_value / dm_value;
div_zero_vfp_flag_ = (dm_value == 0);
+ dd_value = canonicalizeNaN(dd_value);
set_d_register_from_double(vd, dd_value);
} else {
UNIMPLEMENTED(); // Not used by V8.
@@ -2828,9 +2849,9 @@
int vd = instr->Bits(19, 16) | (instr->Bit(7) << 4);
double dd_value = get_double_from_d_register(vd);
int32_t data[2];
- memcpy(data, &dd_value, 8);
+ OS::MemCopy(data, &dd_value, 8);
data[instr->Bit(21)] = get_register(instr->RtValue());
- memcpy(&dd_value, data, 8);
+ OS::MemCopy(&dd_value, data, 8);
set_d_register_from_double(vd, dd_value);
} else if ((instr->VLValue() == 0x1) &&
(instr->VCValue() == 0x0) &&
@@ -2846,6 +2867,7 @@
(z_flag_FPSCR_ << 30) |
(c_flag_FPSCR_ << 29) |
(v_flag_FPSCR_ << 28) |
+ (FPSCR_default_NaN_mode_ << 25) |
(inexact_vfp_flag_ << 4) |
(underflow_vfp_flag_ << 3) |
(overflow_vfp_flag_ << 2) |
@@ -2868,6 +2890,7 @@
z_flag_FPSCR_ = (rt_value >> 30) & 1;
c_flag_FPSCR_ = (rt_value >> 29) & 1;
v_flag_FPSCR_ = (rt_value >> 28) & 1;
+ FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
inexact_vfp_flag_ = (rt_value >> 4) & 1;
underflow_vfp_flag_ = (rt_value >> 3) & 1;
overflow_vfp_flag_ = (rt_value >> 2) & 1;
@@ -3179,13 +3202,13 @@
if (instr->HasL()) {
int32_t data[2];
double d = get_double_from_d_register(vm);
- memcpy(data, &d, 8);
+ OS::MemCopy(data, &d, 8);
set_register(rt, data[0]);
set_register(rn, data[1]);
} else {
int32_t data[] = { get_register(rt), get_register(rn) };
double d;
- memcpy(&d, data, 8);
+ OS::MemCopy(&d, data, 8);
set_d_register_from_double(vm, d);
}
}
@@ -3208,13 +3231,13 @@
ReadW(address + 4, instr)
};
double val;
- memcpy(&val, data, 8);
+ OS::MemCopy(&val, data, 8);
set_d_register_from_double(vd, val);
} else {
// Store double to memory: vstr.
int32_t data[2];
double val = get_double_from_d_register(vd);
- memcpy(data, &val, 8);
+ OS::MemCopy(data, &val, 8);
WriteW(address, data[0], instr);
WriteW(address + 4, data[1], instr);
}
@@ -3437,9 +3460,9 @@
} else {
int buffer[2];
ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
- memcpy(buffer, &d0, sizeof(d0));
+ OS::MemCopy(buffer, &d0, sizeof(d0));
set_dw_register(0, buffer);
- memcpy(buffer, &d1, sizeof(d1));
+ OS::MemCopy(buffer, &d1, sizeof(d1));
set_dw_register(2, buffer);
}
CallInternal(entry);
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index b918ecf..45ae999 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -274,6 +274,7 @@
// Support for VFP.
void Compute_FPSCR_Flags(double val1, double val2);
void Copy_FPSCR_to_APSR();
+ inline double canonicalizeNaN(double value);
// Helper functions to decode common "addressing" modes
int32_t GetShiftRm(Instruction* instr, bool* carry_out);
@@ -347,10 +348,8 @@
void* external_function,
v8::internal::ExternalReference::Type type);
- // For use in calls that take double value arguments.
- void GetFpArgs(double* x, double* y);
- void GetFpArgs(double* x);
- void GetFpArgs(double* x, int32_t* y);
+ // Handle arguments and return value for runtime FP functions.
+ void GetFpArgs(double* x, double* y, int32_t* z);
void SetFpResult(const double& result);
void TrashCallerSaveRegisters();
@@ -381,6 +380,7 @@
// VFP rounding mode. See ARM DDI 0406B Page A2-29.
VFPRoundingMode FPSCR_rounding_mode_;
+ bool FPSCR_default_NaN_mode_;
// VFP FP exception flags architecture state.
bool inv_op_vfp_flag_;
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index f2d45e1..f22acb4 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -417,30 +417,48 @@
}
-// Generate StoreField code, value is passed in r0 register.
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+ Handle<GlobalObject> global,
+ Handle<Name> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ __ mov(scratch, Operand(cell));
+ __ ldr(scratch,
+ FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ cmp(scratch, ip);
+ __ b(ne, miss);
+}
+
+
+// Generate StoreTransition code, value is passed in r0 register.
// When leaving generated code after success, the receiver_reg and name_reg
// may be clobbered. Upon branch to miss_label, the receiver and name
// registers have their original values.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label,
- Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label,
+ Label* miss_restore_name) {
// r0 : value
Label exit;
// Check that the map of the object hasn't changed.
- CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
- : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK, mode);
+ DO_SMI_CHECK, REQUIRE_EXACT_MAP);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -448,7 +466,7 @@
}
// Check that we are allowed to write this.
- if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+ if (object->GetPrototype()->IsJSObject()) {
JSObject* holder;
// holder == object indicates that no property was found.
if (lookup->holder() != *object) {
@@ -466,12 +484,18 @@
// If no property was found, and the holder (the last object in the
// prototype chain) is in slow mode, we need to do a negative lookup on the
// holder.
- if (lookup->holder() == *object &&
- !holder->HasFastProperties() &&
- !holder->IsJSGlobalProxy() &&
- !holder->IsJSGlobalObject()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ if (lookup->holder() == *object) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm,
+ Handle<GlobalObject>(GlobalObject::cast(holder)),
+ name,
+ scratch1,
+ miss_restore_name);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
}
@@ -480,7 +504,7 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+ if (object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
@@ -494,33 +518,113 @@
return;
}
- int index;
- if (!transition.is_null()) {
- // Update the map of the object.
- __ mov(scratch1, Operand(transition));
- __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+ // Update the map of the object.
+ __ mov(scratch1, Operand(transition));
+ __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
- // Update the write barrier for the map field and pass the now unused
- // name_reg as scratch register.
- __ RecordWriteField(receiver_reg,
- HeapObject::kMapOffset,
- scratch1,
- name_reg,
- kLRHasNotBeenSaved,
- kDontSaveFPRegs,
- OMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- index = transition->instance_descriptors()->GetFieldIndex(
- transition->LastAdded());
- } else {
- index = lookup->GetFieldIndex().field_index();
- }
+ // Update the write barrier for the map field and pass the now unused
+ // name_reg as scratch register.
+ __ RecordWriteField(receiver_reg,
+ HeapObject::kMapOffset,
+ scratch1,
+ name_reg,
+ kLRHasNotBeenSaved,
+ kDontSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ int index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= object->map()->inobject_properties();
+ // TODO(verwaest): Share this code as a code stub.
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ str(value_reg, FieldMemOperand(receiver_reg, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ JumpIfSmi(value_reg, &exit);
+
+ // Update the write barrier for the array address.
+ // Pass the now unused name_reg as a scratch register.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(receiver_reg,
+ offset,
+ name_reg,
+ scratch1,
+ kLRHasNotBeenSaved,
+ kDontSaveFPRegs);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array
+ __ ldr(scratch1,
+ FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ str(value_reg, FieldMemOperand(scratch1, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ JumpIfSmi(value_reg, &exit);
+
+ // Update the write barrier for the array address.
+ // Ok to clobber receiver_reg and name_reg, since we return.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(scratch1,
+ offset,
+ name_reg,
+ receiver_reg,
+ kLRHasNotBeenSaved,
+ kDontSaveFPRegs);
+ }
+
+ // Return the value (register r0).
+ ASSERT(value_reg.is(r0));
+ __ bind(&exit);
+ __ Ret();
+}
+
+
+// Generate StoreField code, value is passed in r0 register.
+// When leaving generated code after success, the receiver_reg and name_reg
+// may be clobbered. Upon branch to miss_label, the receiver and name
+// registers have their original values.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ // r0 : value
+ Label exit;
+
+ // Check that the map of the object hasn't changed.
+ __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
+ DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ int index = lookup->GetFieldIndex().field_index();
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ // TODO(verwaest): Share this code as a code stub.
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -926,26 +1030,6 @@
};
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
- Handle<GlobalObject> global,
- Handle<Name> name,
- Register scratch,
- Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
- GlobalObject::EnsurePropertyCell(global, name);
- ASSERT(cell->value()->IsTheHole());
- __ mov(scratch, Operand(cell));
- __ ldr(scratch,
- FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(scratch, ip);
- __ b(ne, miss);
-}
-
-
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
@@ -975,66 +1059,11 @@
Register dst,
Register wordoffset,
Register ival,
- Register fval,
- Register scratch1,
- Register scratch2) {
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- __ vmov(s0, ival);
- __ add(scratch1, dst, Operand(wordoffset, LSL, 2));
- __ vcvt_f32_s32(s0, s0);
- __ vstr(s0, scratch1, 0);
- } else {
- Label not_special, done;
- // Move sign bit from source to destination. This works because the sign
- // bit in the exponent word of the double has the same position and polarity
- // as the 2's complement sign bit in a Smi.
- ASSERT(kBinary32SignMask == 0x80000000u);
-
- __ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
- // Negate value if it is negative.
- __ rsb(ival, ival, Operand::Zero(), LeaveCC, ne);
-
- // We have -1, 0 or 1, which we treat specially. Register ival contains
- // absolute value: it is either equal to 1 (special case of -1 and 1),
- // greater than 1 (not a special case) or less than 1 (special case of 0).
- __ cmp(ival, Operand(1));
- __ b(gt, ¬_special);
-
- // For 1 or -1 we need to or in the 0 exponent (biased).
- static const uint32_t exponent_word_for_1 =
- kBinary32ExponentBias << kBinary32ExponentShift;
-
- __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq);
- __ b(&done);
-
- __ bind(¬_special);
- // Count leading zeros.
- // Gets the wrong answer for 0, but we already checked for that case above.
- Register zeros = scratch2;
- __ CountLeadingZeros(zeros, ival, scratch1);
-
- // Compute exponent and or it into the exponent register.
- __ rsb(scratch1,
- zeros,
- Operand((kBitsPerInt - 1) + kBinary32ExponentBias));
-
- __ orr(fval,
- fval,
- Operand(scratch1, LSL, kBinary32ExponentShift));
-
- // Shift up the source chopping the top bit off.
- __ add(zeros, zeros, Operand(1));
- // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
- __ mov(ival, Operand(ival, LSL, zeros));
- // And the top (top 20 bits).
- __ orr(fval,
- fval,
- Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits));
-
- __ bind(&done);
- __ str(fval, MemOperand(dst, wordoffset, LSL, 2));
- }
+ Register scratch1) {
+ __ vmov(s0, ival);
+ __ add(scratch1, dst, Operand(wordoffset, LSL, 2));
+ __ vcvt_f32_s32(s0, s0);
+ __ vstr(s0, scratch1, 0);
}
@@ -1225,7 +1254,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+ HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1233,13 +1262,6 @@
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- if (!last->HasFastProperties()) {
- __ ldr(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
- __ ldr(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
- __ cmp(scratch2(), Operand(isolate()->factory()->null_value()));
- __ b(ne, &miss);
- }
-
HandlerFrontendFooter(success, &miss);
}
@@ -1599,7 +1621,7 @@
__ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
__ StoreNumberToDoubleElements(
- r4, r0, elements, r3, r5, r2, r9,
+ r4, r0, elements, r5, r2, r3, r9,
&call_builtin, argc * kDoubleSize);
// Save new length.
@@ -2089,11 +2111,6 @@
// -- sp[argc * 4] : receiver
// -----------------------------------
- if (!CpuFeatures::IsSupported(VFP2)) {
- return Handle<Code>::null();
- }
-
- CpuFeatureScope scope_vfp2(masm(), VFP2);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
@@ -3133,36 +3150,6 @@
}
-static bool IsElementTypeSigned(ElementsKind elements_kind) {
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- return true;
-
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_PIXEL_ELEMENTS:
- return false;
-
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- return false;
- }
- return false;
-}
-
-
static void GenerateSmiKeyCheck(MacroAssembler* masm,
Register key,
Register scratch0,
@@ -3170,29 +3157,23 @@
DwVfpRegister double_scratch0,
DwVfpRegister double_scratch1,
Label* fail) {
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- Label key_ok;
- // Check for smi or a smi inside a heap number. We convert the heap
- // number and check if the conversion is exact and fits into the smi
- // range.
- __ JumpIfSmi(key, &key_ok);
- __ CheckMap(key,
- scratch0,
- Heap::kHeapNumberMapRootIndex,
- fail,
- DONT_DO_SMI_CHECK);
- __ sub(ip, key, Operand(kHeapObjectTag));
- __ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
- __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1);
- __ b(ne, fail);
- __ TrySmiTag(scratch0, fail, scratch1);
- __ mov(key, scratch0);
- __ bind(&key_ok);
- } else {
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, fail);
- }
+ Label key_ok;
+ // Check for smi or a smi inside a heap number. We convert the heap
+ // number and check if the conversion is exact and fits into the smi
+ // range.
+ __ JumpIfSmi(key, &key_ok);
+ __ CheckMap(key,
+ scratch0,
+ Heap::kHeapNumberMapRootIndex,
+ fail,
+ DONT_DO_SMI_CHECK);
+ __ sub(ip, key, Operand(kHeapObjectTag));
+ __ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
+ __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1);
+ __ b(ne, fail);
+ __ TrySmiTag(scratch0, fail, scratch1);
+ __ mov(key, scratch0);
+ __ bind(&key_ok);
}
@@ -3262,28 +3243,18 @@
case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(r4, key);
- StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
+ StoreIntAsFloat(masm, r3, r4, r5, r7);
break;
case EXTERNAL_DOUBLE_ELEMENTS:
__ add(r3, r3, Operand(key, LSL, 2));
// r3: effective address of the double element
FloatingPointHelper::Destination destination;
- if (CpuFeatures::IsSupported(VFP2)) {
- destination = FloatingPointHelper::kVFPRegisters;
- } else {
- destination = FloatingPointHelper::kCoreRegisters;
- }
+ destination = FloatingPointHelper::kVFPRegisters;
FloatingPointHelper::ConvertIntToDouble(
masm, r5, destination,
d0, r6, r7, // These are: double_dst, dst_mantissa, dst_exponent.
r4, s2); // These are: scratch2, single_scratch.
- if (destination == FloatingPointHelper::kVFPRegisters) {
- CpuFeatureScope scope(masm, VFP2);
- __ vstr(d0, r3, 0);
- } else {
- __ str(r6, MemOperand(r3, 0));
- __ str(r7, MemOperand(r3, Register::kSizeInBytes));
- }
+ __ vstr(d0, r3, 0);
break;
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
@@ -3313,201 +3284,59 @@
// The WebGL specification leaves the behavior of storing NaN and
// +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero.
- if (CpuFeatures::IsSupported(VFP2)) {
- CpuFeatureScope scope(masm, VFP2);
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- // vldr requires offset to be a multiple of 4 so we can not
- // include -kHeapObjectTag into it.
- __ sub(r5, r0, Operand(kHeapObjectTag));
- __ vldr(d0, r5, HeapNumber::kValueOffset);
- __ add(r5, r3, Operand(key, LSL, 1));
- __ vcvt_f32_f64(s0, d0);
- __ vstr(s0, r5, 0);
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- __ sub(r5, r0, Operand(kHeapObjectTag));
- __ vldr(d0, r5, HeapNumber::kValueOffset);
- __ add(r5, r3, Operand(key, LSL, 2));
- __ vstr(d0, r5, 0);
- } else {
- // Hoisted load. vldr requires offset to be a multiple of 4 so we can
- // not include -kHeapObjectTag into it.
- __ sub(r5, value, Operand(kHeapObjectTag));
- __ vldr(d0, r5, HeapNumber::kValueOffset);
- __ ECMAToInt32VFP(r5, d0, d1, r6, r7, r9);
-
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ strb(r5, MemOperand(r3, key, LSR, 1));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ strh(r5, MemOperand(r3, key, LSL, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ str(r5, MemOperand(r3, key, LSL, 1));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
- }
-
- // Entry registers are intact, r0 holds the value which is the return
- // value.
- __ Ret();
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ // vldr requires offset to be a multiple of 4 so we can not
+ // include -kHeapObjectTag into it.
+ __ sub(r5, r0, Operand(kHeapObjectTag));
+ __ vldr(d0, r5, HeapNumber::kValueOffset);
+ __ add(r5, r3, Operand(key, LSL, 1));
+ __ vcvt_f32_f64(s0, d0);
+ __ vstr(s0, r5, 0);
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+ __ sub(r5, r0, Operand(kHeapObjectTag));
+ __ vldr(d0, r5, HeapNumber::kValueOffset);
+ __ add(r5, r3, Operand(key, LSL, 2));
+ __ vstr(d0, r5, 0);
} else {
- // VFP3 is not available do manual conversions.
- __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
- __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
+ // Hoisted load. vldr requires offset to be a multiple of 4 so we can
+ // not include -kHeapObjectTag into it.
+ __ sub(r5, value, Operand(kHeapObjectTag));
+ __ vldr(d0, r5, HeapNumber::kValueOffset);
+ __ ECMAToInt32(r5, d0, d1, r6, r7, r9);
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- Label done, nan_or_infinity_or_zero;
- static const int kMantissaInHiWordShift =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaInLoWordShift =
- kBitsPerInt - kMantissaInHiWordShift;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ mov(r7, Operand(HeapNumber::kExponentMask));
- __ and_(r9, r5, Operand(r7), SetCC);
- __ b(eq, &nan_or_infinity_or_zero);
-
- __ teq(r9, Operand(r7));
- __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
- __ b(eq, &nan_or_infinity_or_zero);
-
- // Rebias exponent.
- __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
- __ add(r9,
- r9,
- Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
-
- __ cmp(r9, Operand(kBinary32MaxExponent));
- __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
- __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
- __ b(gt, &done);
-
- __ cmp(r9, Operand(kBinary32MinExponent));
- __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
- __ b(lt, &done);
-
- __ and_(r7, r5, Operand(HeapNumber::kSignMask));
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
- __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
- __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
- __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
-
- __ bind(&done);
- __ str(r5, MemOperand(r3, key, LSL, 1));
- // Entry registers are intact, r0 holds the value which is the return
- // value.
- __ Ret();
-
- __ bind(&nan_or_infinity_or_zero);
- __ and_(r7, r5, Operand(HeapNumber::kSignMask));
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
- __ orr(r9, r9, r7);
- __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
- __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
- __ b(&done);
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- __ add(r7, r3, Operand(key, LSL, 2));
- // r7: effective address of destination element.
- __ str(r6, MemOperand(r7, 0));
- __ str(r5, MemOperand(r7, Register::kSizeInBytes));
- __ Ret();
- } else {
- bool is_signed_type = IsElementTypeSigned(elements_kind);
- int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
- int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
-
- Label done, sign;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ mov(r7, Operand(HeapNumber::kExponentMask));
- __ and_(r9, r5, Operand(r7), SetCC);
- __ mov(r5, Operand::Zero(), LeaveCC, eq);
- __ b(eq, &done);
-
- __ teq(r9, Operand(r7));
- __ mov(r5, Operand::Zero(), LeaveCC, eq);
- __ b(eq, &done);
-
- // Unbias exponent.
- __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
- __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
- // If exponent is negative then result is 0.
- __ mov(r5, Operand::Zero(), LeaveCC, mi);
- __ b(mi, &done);
-
- // If exponent is too big then result is minimal value.
- __ cmp(r9, Operand(meaningfull_bits - 1));
- __ mov(r5, Operand(min_value), LeaveCC, ge);
- __ b(ge, &done);
-
- __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
- __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
-
- __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
- __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
- __ b(pl, &sign);
-
- __ rsb(r9, r9, Operand::Zero());
- __ mov(r5, Operand(r5, LSL, r9));
- __ rsb(r9, r9, Operand(meaningfull_bits));
- __ orr(r5, r5, Operand(r6, LSR, r9));
-
- __ bind(&sign);
- __ teq(r7, Operand::Zero());
- __ rsb(r5, r5, Operand::Zero(), LeaveCC, ne);
-
- __ bind(&done);
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ strb(r5, MemOperand(r3, key, LSR, 1));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ strh(r5, MemOperand(r3, key, LSL, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ str(r5, MemOperand(r3, key, LSL, 1));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
+ switch (elements_kind) {
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ __ strb(r5, MemOperand(r3, key, LSR, 1));
+ break;
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ __ strh(r5, MemOperand(r3, key, LSL, 0));
+ break;
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ __ str(r5, MemOperand(r3, key, LSL, 1));
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
+ break;
}
}
+
+ // Entry registers are intact, r0 holds the value which is the return
+ // value.
+ __ Ret();
}
// Slow case, key and receiver still in r0 and r1.
@@ -3757,9 +3586,9 @@
// All registers after this are overwritten.
elements_reg,
scratch1,
- scratch2,
scratch3,
scratch4,
+ scratch2,
&transition_elements_kind);
__ Ret();
diff --git a/src/array.js b/src/array.js
index 936d008..54f0b48 100644
--- a/src/array.js
+++ b/src/array.js
@@ -1017,7 +1017,7 @@
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver)) {
+ } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
receiver = ToObject(receiver);
}
@@ -1068,9 +1068,10 @@
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver)) {
+ } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
receiver = ToObject(receiver);
}
+
if (%DebugCallbackSupportsStepping(f)) {
for (var i = 0; i < length; i++) {
if (i in array) {
@@ -1111,7 +1112,7 @@
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver)) {
+ } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
receiver = ToObject(receiver);
}
@@ -1154,7 +1155,7 @@
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver)) {
+ } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
receiver = ToObject(receiver);
}
@@ -1196,7 +1197,7 @@
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver)) {
+ } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
receiver = ToObject(receiver);
}
@@ -1453,8 +1454,10 @@
// -------------------------------------------------------------------
+
function SetUpArray() {
%CheckIsBootstrapping();
+
// Set up non-enumerable constructor property on the Array.prototype
// object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
diff --git a/src/assembler.cc b/src/assembler.cc
index deef28b..5bde8c5 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -191,11 +191,9 @@
uint64_t mask = static_cast<uint64_t>(1) << f;
// TODO(svenpanne) This special case below doesn't belong here!
#if V8_TARGET_ARCH_ARM
- // VFP2 and ARMv7 are implied by VFP3.
+ // ARMv7 is implied by VFP3.
if (f == VFP3) {
- mask |=
- static_cast<uint64_t>(1) << VFP2 |
- static_cast<uint64_t>(1) << ARMv7;
+ mask |= static_cast<uint64_t>(1) << ARMv7;
}
#endif
assembler_->set_enabled_cpu_features(old_enabled_ | mask);
@@ -1191,6 +1189,20 @@
}
+ExternalReference ExternalReference::old_data_space_allocation_top_address(
+ Isolate* isolate) {
+ return ExternalReference(
+ isolate->heap()->OldDataSpaceAllocationTopAddress());
+}
+
+
+ExternalReference ExternalReference::old_data_space_allocation_limit_address(
+ Isolate* isolate) {
+ return ExternalReference(
+ isolate->heap()->OldDataSpaceAllocationLimitAddress());
+}
+
+
ExternalReference ExternalReference::handle_scope_level_address(
Isolate* isolate) {
return ExternalReference(HandleScope::current_level_address(isolate));
diff --git a/src/assembler.h b/src/assembler.h
index e26b525..381ae0a 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -753,6 +753,10 @@
Isolate* isolate);
static ExternalReference old_pointer_space_allocation_limit_address(
Isolate* isolate);
+ static ExternalReference old_data_space_allocation_top_address(
+ Isolate* isolate);
+ static ExternalReference old_data_space_allocation_limit_address(
+ Isolate* isolate);
static ExternalReference double_fp_operation(Token::Value operation,
Isolate* isolate);
diff --git a/src/ast.cc b/src/ast.cc
index 7d7a5b2..e8b065c 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -509,6 +509,11 @@
}
LookupResult lookup(type->GetIsolate());
while (true) {
+ // If a dictionary map is found in the prototype chain before the actual
+ // target, a new target can always appear. In that case, bail out.
+ // TODO(verwaest): Alternatively a runtime negative lookup on the normal
+ // receiver or prototype could be added.
+ if (type->is_dictionary_map()) return false;
type->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsFound()) {
switch (lookup.type()) {
@@ -534,7 +539,6 @@
if (!type->prototype()->IsJSObject()) return false;
// Go up the prototype chain, recording where we are currently.
holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
- if (!holder_->HasFastProperties()) return false;
type = Handle<Map>(holder()->map());
}
}
diff --git a/src/ast.h b/src/ast.h
index dddfc83..b733138 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1811,7 +1811,8 @@
Token::Value op_;
bool is_prefix_ : 1;
bool is_monomorphic_ : 1;
- KeyedAccessStoreMode store_mode_: 4;
+ KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
+ // must have extra bit.
Expression* expression_;
int pos_;
const BailoutId assignment_id_;
@@ -1953,7 +1954,8 @@
const BailoutId assignment_id_;
bool is_monomorphic_ : 1;
- KeyedAccessStoreMode store_mode_ : 4;
+ KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
+ // must have extra bit.
SmallMapList receiver_types_;
};
@@ -1962,21 +1964,25 @@
public:
DECLARE_NODE_TYPE(Yield)
+ Expression* generator_object() const { return generator_object_; }
Expression* expression() const { return expression_; }
bool is_delegating_yield() const { return is_delegating_yield_; }
virtual int position() const { return pos_; }
protected:
Yield(Isolate* isolate,
+ Expression* generator_object,
Expression* expression,
bool is_delegating_yield,
int pos)
: Expression(isolate),
+ generator_object_(generator_object),
expression_(expression),
is_delegating_yield_(is_delegating_yield),
pos_(pos) { }
private:
+ Expression* generator_object_;
Expression* expression_;
bool is_delegating_yield_;
int pos_;
@@ -2958,9 +2964,12 @@
VISIT_AND_RETURN(Assignment, assign)
}
- Yield* NewYield(Expression* expression, bool is_delegating_yield, int pos) {
- Yield* yield =
- new(zone_) Yield(isolate_, expression, is_delegating_yield, pos);
+ Yield* NewYield(Expression *generator_object,
+ Expression* expression,
+ bool is_delegating_yield,
+ int pos) {
+ Yield* yield = new(zone_) Yield(
+ isolate_, generator_object, expression, is_delegating_yield, pos);
VISIT_AND_RETURN(Yield, yield)
}
diff --git a/src/atomicops_internals_x86_gcc.cc b/src/atomicops_internals_x86_gcc.cc
index 181c202..b5078cf 100644
--- a/src/atomicops_internals_x86_gcc.cc
+++ b/src/atomicops_internals_x86_gcc.cc
@@ -31,6 +31,7 @@
#include <string.h>
#include "atomicops.h"
+#include "platform.h"
// This file only makes sense with atomicops_internals_x86_gcc.h -- it
// depends on structs that are defined in that file. If atomicops.h
@@ -84,9 +85,9 @@
// Get vendor string (issue CPUID with eax = 0)
cpuid(eax, ebx, ecx, edx, 0);
char vendor[13];
- memcpy(vendor, &ebx, 4);
- memcpy(vendor + 4, &edx, 4);
- memcpy(vendor + 8, &ecx, 4);
+ v8::internal::OS::MemCopy(vendor, &ebx, 4);
+ v8::internal::OS::MemCopy(vendor + 4, &edx, 4);
+ v8::internal::OS::MemCopy(vendor + 8, &ecx, 4);
vendor[12] = 0;
// get feature flags in ecx/edx, and family/model in eax
diff --git a/src/atomicops_internals_x86_gcc.h b/src/atomicops_internals_x86_gcc.h
index 6e55b50..e58d598 100644
--- a/src/atomicops_internals_x86_gcc.h
+++ b/src/atomicops_internals_x86_gcc.h
@@ -168,7 +168,7 @@
return *ptr;
}
-#if defined(__x86_64__)
+#if defined(__x86_64__) && defined(V8_HOST_ARCH_64_BIT)
// 64-bit low-level operations on 64-bit platform.
diff --git a/src/bignum.cc b/src/bignum.cc
index 9436322..c8b61ee 100644
--- a/src/bignum.cc
+++ b/src/bignum.cc
@@ -735,6 +735,13 @@
void Bignum::SubtractTimes(const Bignum& other, int factor) {
+#ifdef DEBUG
+ Bignum a, b;
+ a.AssignBignum(*this);
+ b.AssignBignum(other);
+ b.MultiplyByUInt32(factor);
+ a.SubtractBignum(b);
+#endif
ASSERT(exponent_ <= other.exponent_);
if (factor < 3) {
for (int i = 0; i < factor; ++i) {
@@ -758,9 +765,9 @@
Chunk difference = bigits_[i] - borrow;
bigits_[i] = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
- ++i;
}
Clamp();
+ ASSERT(Bignum::Equal(a, *this));
}
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index f57a1f6..12f0cda 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -199,6 +199,8 @@
const char* name,
ElementsKind elements_kind);
bool InstallNatives();
+
+ void InstallTypedArray(const char* name);
bool InstallExperimentalNatives();
void InstallBuiltinFunctionIds();
void InstallJSFunctionResultCaches();
@@ -303,14 +305,11 @@
v8::ExtensionConfiguration* extensions) {
HandleScope scope(isolate_);
Genesis genesis(isolate_, global_object, global_template, extensions);
- if (!genesis.result().is_null()) {
- Handle<Object> ctx(isolate_->global_handles()->Create(*genesis.result()));
- Handle<Context> env = Handle<Context>::cast(ctx);
- if (InstallExtensions(env, extensions)) {
- return env;
- }
+ Handle<Context> env = genesis.result();
+ if (env.is_null() || !InstallExtensions(env, extensions)) {
+ return Handle<Context>();
}
- return Handle<Context>();
+ return scope.CloseAndEscape(env);
}
@@ -477,25 +476,10 @@
native_context()->set_object_function(*object_fun);
// Allocate a new prototype for the object function.
- Handle<Map> object_prototype_map =
- factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
- Handle<DescriptorArray> prototype_descriptors(
- factory->NewDescriptorArray(0, 1));
- DescriptorArray::WhitenessWitness witness(*prototype_descriptors);
-
- Handle<Foreign> object_prototype(
- factory->NewForeign(&Accessors::ObjectPrototype));
- PropertyAttributes attribs = static_cast<PropertyAttributes>(DONT_ENUM);
- object_prototype_map->set_instance_descriptors(*prototype_descriptors);
-
- { // Add __proto__.
- CallbacksDescriptor d(heap->proto_string(), *object_prototype, attribs);
- object_prototype_map->AppendDescriptor(&d, witness);
- }
-
- Handle<JSObject> prototype = factory->NewJSObjectFromMap(
- object_prototype_map,
+ Handle<JSObject> prototype = factory->NewJSObject(
+ isolate->object_function(),
TENURED);
+
native_context()->set_initial_object_prototype(*prototype);
SetPrototype(object_fun, prototype);
}
@@ -1276,6 +1260,14 @@
}
+void Genesis::InstallTypedArray(const char* name) {
+ Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
+ InstallFunction(global, name, JS_TYPED_ARRAY_TYPE,
+ JSTypedArray::kSize, isolate()->initial_object_prototype(),
+ Builtins::kIllegal, true);
+}
+
+
void Genesis::InitializeExperimentalGlobal() {
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
@@ -1293,33 +1285,80 @@
if (FLAG_harmony_collections) {
{ // -- S e t
- Handle<JSObject> prototype =
- factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
- prototype, Builtins::kIllegal, true);
+ isolate()->initial_object_prototype(),
+ Builtins::kIllegal, true);
}
{ // -- M a p
- Handle<JSObject> prototype =
- factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize,
- prototype, Builtins::kIllegal, true);
+ isolate()->initial_object_prototype(),
+ Builtins::kIllegal, true);
}
{ // -- W e a k M a p
- Handle<JSObject> prototype =
- factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
- prototype, Builtins::kIllegal, true);
+ isolate()->initial_object_prototype(),
+ Builtins::kIllegal, true);
}
}
if (FLAG_harmony_typed_arrays) {
- { // -- A r r a y B u f f e r
- Handle<JSObject> prototype =
- factory()->NewJSObject(isolate()->object_function(), TENURED);
+ { // -- A r r a y B u f f e r
InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
- JSArrayBuffer::kSize, prototype,
+ JSArrayBuffer::kSize,
+ isolate()->initial_object_prototype(),
Builtins::kIllegal, true);
}
+ {
+ // -- T y p e d A r r a y s
+ InstallTypedArray("__Int8Array");
+ InstallTypedArray("__Uint8Array");
+ InstallTypedArray("__Int16Array");
+ InstallTypedArray("__Uint16Array");
+ InstallTypedArray("__Int32Array");
+ InstallTypedArray("__Uint32Array");
+ InstallTypedArray("__Float32Array");
+ InstallTypedArray("__Float64Array");
+ }
+ }
+
+ if (FLAG_harmony_generators) {
+ // Create generator meta-objects and install them on the builtins object.
+ Handle<JSObject> builtins(native_context()->builtins());
+ Handle<JSObject> generator_object_prototype =
+ factory()->NewJSObject(isolate()->object_function(), TENURED);
+ Handle<JSFunction> generator_function_prototype =
+ InstallFunction(builtins, "GeneratorFunctionPrototype",
+ JS_FUNCTION_TYPE, JSFunction::kHeaderSize,
+ generator_object_prototype, Builtins::kIllegal,
+ false);
+ InstallFunction(builtins, "GeneratorFunction",
+ JS_FUNCTION_TYPE, JSFunction::kSize,
+ generator_function_prototype, Builtins::kIllegal,
+ false);
+
+ // Create maps for generator functions and their prototypes. Store those
+ // maps in the native context.
+ Handle<Map> function_map(native_context()->function_map());
+ Handle<Map> generator_function_map = factory()->CopyMap(function_map);
+ generator_function_map->set_prototype(*generator_function_prototype);
+ native_context()->set_generator_function_map(*generator_function_map);
+
+ Handle<Map> strict_mode_function_map(
+ native_context()->strict_mode_function_map());
+ Handle<Map> strict_mode_generator_function_map = factory()->CopyMap(
+ strict_mode_function_map);
+ strict_mode_generator_function_map->set_prototype(
+ *generator_function_prototype);
+ native_context()->set_strict_mode_generator_function_map(
+ *strict_mode_generator_function_map);
+
+ Handle<Map> object_map(native_context()->object_function()->initial_map());
+ Handle<Map> generator_object_prototype_map = factory()->CopyMap(
+ object_map, 0);
+ generator_object_prototype_map->set_prototype(
+ *generator_object_prototype);
+ native_context()->set_generator_object_prototype_map(
+ *generator_object_prototype_map);
}
}
@@ -1933,6 +1972,11 @@
"native typedarray.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
+ if (FLAG_harmony_generators &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native generator.js") == 0) {
+ if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+ }
}
InstallExperimentalNativeFunctions();
diff --git a/src/builtins-decls.h b/src/builtins-decls.h
new file mode 100644
index 0000000..beb5dd1
--- /dev/null
+++ b/src/builtins-decls.h
@@ -0,0 +1,40 @@
+// Copyright 2013 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_BUILTINS_DECLS_H_
+#define V8_BUILTINS_DECLS_H_
+
+#include "arguments.h"
+
+namespace v8 {
+namespace internal {
+
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure);
+
+} } // namespace v8::internal
+
+#endif // V8_BUILTINS_DECLS_H_
diff --git a/src/builtins.cc b/src/builtins.cc
index f8d562b..56c0501 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -125,23 +125,31 @@
#ifdef DEBUG
-#define BUILTIN(name) \
- MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
- name##ArgumentsType args, Isolate* isolate); \
- MUST_USE_RESULT static MaybeObject* Builtin_##name( \
- name##ArgumentsType args, Isolate* isolate) { \
- ASSERT(isolate == Isolate::Current()); \
- args.Verify(); \
- return Builtin_Impl_##name(args, isolate); \
- } \
- MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
+#define BUILTIN(name) \
+ MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
+ name##ArgumentsType args, Isolate* isolate); \
+ MUST_USE_RESULT static MaybeObject* Builtin_##name( \
+ int args_length, Object** args_object, Isolate* isolate) { \
+ name##ArgumentsType args(args_length, args_object); \
+ ASSERT(isolate == Isolate::Current()); \
+ args.Verify(); \
+ return Builtin_Impl_##name(args, isolate); \
+ } \
+ MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
name##ArgumentsType args, Isolate* isolate)
#else // For release mode.
-#define BUILTIN(name) \
- static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
-
+#define BUILTIN(name) \
+ static MaybeObject* Builtin_impl##name( \
+ name##ArgumentsType args, Isolate* isolate); \
+ static MaybeObject* Builtin_##name( \
+ int args_length, Object** args_object, Isolate* isolate) { \
+ name##ArgumentsType args(args_length, args_object); \
+ return Builtin_impl##name(args, isolate); \
+ } \
+ static MaybeObject* Builtin_impl##name( \
+ name##ArgumentsType args, Isolate* isolate)
#endif
@@ -323,9 +331,9 @@
int src_index,
int len) {
if (len == 0) return;
- memmove(dst->data_start() + dst_index,
- src->data_start() + src_index,
- len * kDoubleSize);
+ OS::MemMove(dst->data_start() + dst_index,
+ src->data_start() + src_index,
+ len * kDoubleSize);
}
diff --git a/src/builtins.h b/src/builtins.h
index 12ed56a..ee607ad 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -274,8 +274,6 @@
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1)
-MaybeObject* ArrayConstructor_StubFailure(Arguments args, Isolate* isolate);
-
class BuiltinFunctionTable;
class ObjectVisitor;
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index ee903ae..02c0091 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -147,6 +147,8 @@
AddSimulate(BailoutId::StubEntry());
+ NoObservableSideEffectsScope no_effects(this);
+
HValue* return_value = BuildCodeStub();
// We might have extra expressions to pop from the stack in addition to the
@@ -189,6 +191,70 @@
template <>
+HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
+ Zone* zone = this->zone();
+ Factory* factory = isolate()->factory();
+ AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
+ FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
+ int length = casted_stub()->length();
+
+ HInstruction* boilerplate =
+ AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
+ GetParameter(1),
+ NULL,
+ FAST_ELEMENTS));
+
+ CheckBuilder builder(this);
+ builder.CheckNotUndefined(boilerplate);
+
+ if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
+ HValue* elements =
+ AddInstruction(new(zone) HLoadElements(boilerplate, NULL));
+
+ IfBuilder if_fixed_cow(this);
+ if_fixed_cow.BeginIfMapEquals(elements, factory->fixed_cow_array_map());
+ environment()->Push(BuildCloneShallowArray(context(),
+ boilerplate,
+ alloc_site_mode,
+ FAST_ELEMENTS,
+ 0/*copy-on-write*/));
+ if_fixed_cow.BeginElse();
+
+ IfBuilder if_fixed(this);
+ if_fixed.BeginIfMapEquals(elements, factory->fixed_array_map());
+ environment()->Push(BuildCloneShallowArray(context(),
+ boilerplate,
+ alloc_site_mode,
+ FAST_ELEMENTS,
+ length));
+ if_fixed.BeginElse();
+
+ environment()->Push(BuildCloneShallowArray(context(),
+ boilerplate,
+ alloc_site_mode,
+ FAST_DOUBLE_ELEMENTS,
+ length));
+ } else {
+ ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
+ environment()->Push(BuildCloneShallowArray(context(),
+ boilerplate,
+ alloc_site_mode,
+ elements_kind,
+ length));
+ }
+
+ return environment()->Pop();
+}
+
+
+Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
+ CodeStubGraphBuilder<FastCloneShallowArrayStub> builder(this);
+ LChunk* chunk = OptimizeGraph(builder.CreateGraph());
+ return chunk->Codegen(Code::COMPILED_STUB);
+}
+
+
+template <>
HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
Zone* zone = this->zone();
Factory* factory = isolate()->factory();
@@ -230,7 +296,6 @@
factory->empty_string(),
value,
true, i));
- AddSimulate(BailoutId::StubEntry());
}
builder.End();
@@ -264,7 +329,6 @@
GetParameter(0), GetParameter(1), GetParameter(2), NULL,
casted_stub()->is_js_array(), casted_stub()->elements_kind(),
true, casted_stub()->store_mode(), Representation::Tagged());
- AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE);
return GetParameter(2);
}
@@ -308,7 +372,7 @@
AddInstruction(new(zone) HFixedArrayBaseLength(elements));
HValue* new_elements =
- BuildAllocateElements(context(), to_kind, elements_length);
+ BuildAllocateAndInitializeElements(context(), to_kind, elements_length);
BuildCopyElements(context(), elements,
casted_stub()->from_kind(), new_elements,
@@ -320,13 +384,11 @@
factory->elements_field_string(),
new_elements, true,
JSArray::kElementsOffset));
- AddSimulate(BailoutId::StubEntry());
if_builder.End();
AddInstruction(new(zone) HStoreNamedField(js_array, factory->length_string(),
map, true, JSArray::kMapOffset));
- AddSimulate(BailoutId::StubEntry());
return js_array;
}
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index eff0f7f..ad418d6 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -619,8 +619,10 @@
void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
- StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).GetCode(isolate);
- StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).GetCode(isolate);
+ StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
+ StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);
+ stub1.GetCode(isolate)->set_is_pregenerated(true);
+ stub2.GetCode(isolate)->set_is_pregenerated(true);
}
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 99ff515..60c4fb9 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -393,17 +393,24 @@
class FastNewClosureStub : public PlatformCodeStub {
public:
- explicit FastNewClosureStub(LanguageMode language_mode)
- : language_mode_(language_mode) { }
+ explicit FastNewClosureStub(LanguageMode language_mode, bool is_generator)
+ : language_mode_(language_mode),
+ is_generator_(is_generator) { }
void Generate(MacroAssembler* masm);
private:
+ class StrictModeBits: public BitField<bool, 0, 1> {};
+ class IsGeneratorBits: public BitField<bool, 1, 1> {};
+
Major MajorKey() { return FastNewClosure; }
- int MinorKey() { return language_mode_ == CLASSIC_MODE
- ? kNonStrictMode : kStrictMode; }
+ int MinorKey() {
+ return StrictModeBits::encode(language_mode_ != CLASSIC_MODE) |
+ IsGeneratorBits::encode(is_generator_);
+ }
LanguageMode language_mode_;
+ bool is_generator_;
};
@@ -443,7 +450,7 @@
};
-class FastCloneShallowArrayStub : public PlatformCodeStub {
+class FastCloneShallowArrayStub : public HydrogenCodeStub {
public:
// Maximum length of copied elements array.
static const int kMaximumClonedLength = 8;
@@ -467,7 +474,31 @@
ASSERT_LE(length_, kMaximumClonedLength);
}
- void Generate(MacroAssembler* masm);
+ Mode mode() const { return mode_; }
+ int length() const { return length_; }
+ AllocationSiteMode allocation_site_mode() const {
+ return allocation_site_mode_;
+ }
+
+ ElementsKind ComputeElementsKind() const {
+ switch (mode()) {
+ case CLONE_ELEMENTS:
+ case COPY_ON_WRITE_ELEMENTS:
+ return FAST_ELEMENTS;
+ case CLONE_DOUBLE_ELEMENTS:
+ return FAST_DOUBLE_ELEMENTS;
+ case CLONE_ANY_ELEMENTS:
+ /*fall-through*/;
+ }
+ UNREACHABLE();
+ return LAST_ELEMENTS_KIND;
+ }
+
+ virtual Handle<Code> GenerateCode();
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
private:
Mode mode_;
@@ -746,7 +777,7 @@
private:
Token::Value op_;
OverwriteMode mode_;
- bool platform_specific_bit_; // Indicates SSE3 on IA32, VFP2 on ARM.
+ bool platform_specific_bit_; // Indicates SSE3 on IA32.
// Operand type information determined at runtime.
BinaryOpIC::TypeInfo left_type_;
@@ -1604,18 +1635,25 @@
class StubFailureTrampolineStub : public PlatformCodeStub {
public:
explicit StubFailureTrampolineStub(StubFunctionMode function_mode)
- : function_mode_(function_mode) {}
+ : fp_registers_(CanUseFPRegisters()), function_mode_(function_mode) {}
virtual bool IsPregenerated() { return true; }
static void GenerateAheadOfTime(Isolate* isolate);
private:
+ class FPRegisters: public BitField<bool, 0, 1> {};
+ class FunctionModeField: public BitField<StubFunctionMode, 1, 1> {};
+
Major MajorKey() { return StubFailureTrampoline; }
- int MinorKey() { return static_cast<int>(function_mode_); }
+ int MinorKey() {
+ return FPRegisters::encode(fp_registers_) |
+ FunctionModeField::encode(function_mode_);
+ }
void Generate(MacroAssembler* masm);
+ bool fp_registers_;
StubFunctionMode function_mode_;
DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub);
diff --git a/src/collection.js b/src/collection.js
index c872efb..950c7e7 100644
--- a/src/collection.js
+++ b/src/collection.js
@@ -27,16 +27,20 @@
"use strict";
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
var $Set = global.Set;
var $Map = global.Map;
var $WeakMap = global.WeakMap;
-//-------------------------------------------------------------------
-
// Global sentinel to be used instead of undefined keys, which are not
// supported internally but required for Harmony sets and maps.
var undefined_sentinel = {};
+// -------------------------------------------------------------------
+// Harmony Set
function SetConstructor() {
if (%_IsConstructCall()) {
@@ -107,6 +111,31 @@
}
+// -------------------------------------------------------------------
+
+function SetUpSet() {
+ %CheckIsBootstrapping();
+
+ %SetCode($Set, SetConstructor);
+ %FunctionSetPrototype($Set, new $Object());
+ %SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
+
+ // Set up the non-enumerable functions on the Set prototype object.
+ InstallGetter($Set.prototype, "size", SetGetSize);
+ InstallFunctions($Set.prototype, DONT_ENUM, $Array(
+ "add", SetAdd,
+ "has", SetHas,
+ "delete", SetDelete,
+ "clear", SetClear
+ ));
+}
+
+SetUpSet();
+
+
+// -------------------------------------------------------------------
+// Harmony Map
+
function MapConstructor() {
if (%_IsConstructCall()) {
%MapInitialize(this);
@@ -183,6 +212,32 @@
}
+// -------------------------------------------------------------------
+
+function SetUpMap() {
+ %CheckIsBootstrapping();
+
+ %SetCode($Map, MapConstructor);
+ %FunctionSetPrototype($Map, new $Object());
+ %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
+
+ // Set up the non-enumerable functions on the Map prototype object.
+ InstallGetter($Map.prototype, "size", MapGetSize);
+ InstallFunctions($Map.prototype, DONT_ENUM, $Array(
+ "get", MapGet,
+ "set", MapSet,
+ "has", MapHas,
+ "delete", MapDelete,
+ "clear", MapClear
+ ));
+}
+
+SetUpMap();
+
+
+// -------------------------------------------------------------------
+// Harmony WeakMap
+
function WeakMapConstructor() {
if (%_IsConstructCall()) {
%WeakMapInitialize(this);
@@ -239,42 +294,14 @@
return %WeakMapDelete(this, key);
}
+
// -------------------------------------------------------------------
-(function () {
+function SetUpWeakMap() {
%CheckIsBootstrapping();
- // Set up the Set and Map constructor function.
- %SetCode($Set, SetConstructor);
- %SetCode($Map, MapConstructor);
-
- // Set up the constructor property on the Set and Map prototype object.
- %SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
- %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
-
- // Set up the non-enumerable functions on the Set prototype object.
- InstallGetter($Set.prototype, "size", SetGetSize);
- InstallFunctions($Set.prototype, DONT_ENUM, $Array(
- "add", SetAdd,
- "has", SetHas,
- "delete", SetDelete,
- "clear", SetClear
- ));
-
- // Set up the non-enumerable functions on the Map prototype object.
- InstallGetter($Map.prototype, "size", MapGetSize);
- InstallFunctions($Map.prototype, DONT_ENUM, $Array(
- "get", MapGet,
- "set", MapSet,
- "has", MapHas,
- "delete", MapDelete,
- "clear", MapClear
- ));
-
- // Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor);
-
- // Set up the constructor property on the WeakMap prototype object.
+ %FunctionSetPrototype($WeakMap, new $Object());
%SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
// Set up the non-enumerable functions on the WeakMap prototype object.
@@ -284,4 +311,6 @@
"has", WeakMapHas,
"delete", WeakMapDelete
));
-})();
+}
+
+SetUpWeakMap();
diff --git a/src/compiler.cc b/src/compiler.cc
index 6f9b901..184429b 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -520,14 +520,15 @@
// Only allow non-global compiles for eval.
ASSERT(info->is_eval() || info->is_global());
- ParsingFlags flags = kNoParsingFlags;
- if ((info->pre_parse_data() != NULL ||
- String::cast(script->source())->length() > FLAG_min_preparse_length) &&
- !DebuggerWantsEagerCompilation(info)) {
- flags = kAllowLazy;
- }
- if (!ParserApi::Parse(info, flags)) {
- return Handle<SharedFunctionInfo>::null();
+ {
+ Parser parser(info);
+ if ((info->pre_parse_data() != NULL ||
+ String::cast(script->source())->length() > FLAG_min_preparse_length) &&
+ !DebuggerWantsEagerCompilation(info))
+ parser.set_allow_lazy(true);
+ if (!parser.Parse()) {
+ return Handle<SharedFunctionInfo>::null();
+ }
}
// Measure how long it takes to do the compilation; only take the
@@ -864,7 +865,7 @@
if (InstallCodeFromOptimizedCodeMap(info)) return true;
// Generate the AST for the lazily compiled function.
- if (ParserApi::Parse(info, kNoParsingFlags)) {
+ if (Parser::Parse(info)) {
// Measure how long it takes to do the lazy compilation; only take the
// rest of the function into account to avoid overlap with the lazy
// parsing statistics.
@@ -932,7 +933,7 @@
return;
}
- if (ParserApi::Parse(*info, kNoParsingFlags)) {
+ if (Parser::Parse(*info)) {
LanguageMode language_mode = info->function()->language_mode();
info->SetLanguageMode(language_mode);
shared->set_language_mode(language_mode);
@@ -957,18 +958,18 @@
}
}
- if (shared->code()->stack_check_patched_for_osr()) {
+ if (shared->code()->back_edges_patched_for_osr()) {
// At this point we either put the function on recompilation queue or
// aborted optimization. In either case we want to continue executing
// the unoptimized code without running into OSR. If the unoptimized
// code has been patched for OSR, unpatch it.
InterruptStub interrupt_stub;
- Handle<Code> check_code = interrupt_stub.GetCode(isolate);
+ Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
Handle<Code> replacement_code =
isolate->builtins()->OnStackReplacement();
- Deoptimizer::RevertStackCheckCode(shared->code(),
- *check_code,
- *replacement_code);
+ Deoptimizer::RevertInterruptCode(shared->code(),
+ *interrupt_code,
+ *replacement_code);
}
if (isolate->has_pending_exception()) isolate->clear_pending_exception();
diff --git a/src/contexts.h b/src/contexts.h
index a0ba2f7..abeb812 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -165,6 +165,11 @@
V(PROXY_ENUMERATE_INDEX, JSFunction, proxy_enumerate) \
V(OBSERVERS_NOTIFY_CHANGE_INDEX, JSFunction, observers_notify_change) \
V(OBSERVERS_DELIVER_CHANGES_INDEX, JSFunction, observers_deliver_changes) \
+ V(GENERATOR_FUNCTION_MAP_INDEX, Map, generator_function_map) \
+ V(STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX, Map, \
+ strict_mode_generator_function_map) \
+ V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \
+ generator_object_prototype_map) \
V(RANDOM_SEED_INDEX, ByteArray, random_seed)
// JSFunctions are pairs (context, function code), sometimes also called
@@ -295,6 +300,9 @@
PROXY_ENUMERATE_INDEX,
OBSERVERS_NOTIFY_CHANGE_INDEX,
OBSERVERS_DELIVER_CHANGES_INDEX,
+ GENERATOR_FUNCTION_MAP_INDEX,
+ STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX,
+ GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
RANDOM_SEED_INDEX,
// Properties from here are treated as weak references by the full GC.
@@ -439,6 +447,16 @@
return kHeaderSize + index * kPointerSize - kHeapObjectTag;
}
+ static int FunctionMapIndex(LanguageMode language_mode, bool is_generator) {
+ return is_generator
+ ? (language_mode == CLASSIC_MODE
+ ? GENERATOR_FUNCTION_MAP_INDEX
+ : STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX)
+ : (language_mode == CLASSIC_MODE
+ ? FUNCTION_MAP_INDEX
+ : STRICT_MODE_FUNCTION_MAP_INDEX);
+ }
+
static const int kSize = kHeaderSize + NATIVE_CONTEXT_SLOTS * kPointerSize;
// GC support.
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index 7edaf22..eb718d6 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -77,7 +77,7 @@
uint32_t result;
Address mantissa_ptr = reinterpret_cast<Address>(&x);
// Copy least significant 32 bits of mantissa.
- memcpy(&result, mantissa_ptr, sizeof(result));
+ OS::MemCopy(&result, mantissa_ptr, sizeof(result));
return negative ? ~result + 1 : result;
}
// Large number (outside uint32 range), Infinity or NaN.
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 7979eb4..47c2a94 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -445,7 +445,7 @@
generator_ = new ProfileGenerator(profiles_);
processor_ = new ProfilerEventsProcessor(generator_);
is_profiling_ = true;
- processor_->Start();
+ processor_->StartSynchronously();
// Enumerate stuff we already have in the heap.
if (isolate_->heap()->HasBeenSetUp()) {
if (!FLAG_prof_browser_mode) {
@@ -459,11 +459,11 @@
}
// Enable stack sampling.
Sampler* sampler = reinterpret_cast<Sampler*>(isolate_->logger()->ticker_);
+ sampler->IncreaseProfilingDepth();
if (!sampler->IsActive()) {
sampler->Start();
need_to_stop_sampler_ = true;
}
- sampler->IncreaseProfilingDepth();
}
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 89d9c81..6e2b0e0 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -31,6 +31,7 @@
#include "allocation.h"
#include "atomicops.h"
#include "circular-queue.h"
+#include "sampler.h"
#include "unbound-queue.h"
namespace v8 {
diff --git a/src/d8.cc b/src/d8.cc
index b57e390..8f6e384 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -45,6 +45,10 @@
#include "../include/v8-testing.h"
#endif // V8_SHARED
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+#include "third_party/vtune/v8-vtune.h"
+#endif
+
#include "d8.h"
#ifndef V8_SHARED
@@ -144,6 +148,11 @@
Handle<String> DumbLineEditor::Prompt(const char* prompt) {
printf("%s", prompt);
+#if defined(__native_client__)
+ // Native Client libc is used to being embedded in Chrome and
+ // has trouble recognizing when to flush.
+ fflush(stdout);
+#endif
return Shell::ReadFromStdin(isolate_);
}
@@ -1921,6 +1930,9 @@
DumbLineEditor dumb_line_editor(isolate);
{
Initialize(isolate);
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+ vTune::InitilizeVtuneForV8();
+#endif
Symbols symbols(isolate);
InitializeDebugger(isolate);
diff --git a/src/d8.gyp b/src/d8.gyp
index cce8f2a..ea043dc 100644
--- a/src/d8.gyp
+++ b/src/d8.gyp
@@ -29,6 +29,8 @@
'includes': ['../build/common.gypi'],
'variables': {
'console%': '',
+ # Enable support for Intel VTune. Supported on ia32/x64 only
+ 'v8_enable_vtunejit%': 0,
},
'targets': [
{
@@ -70,6 +72,11 @@
}],
],
}],
+ ['v8_enable_vtunejit==1', {
+ 'dependencies': [
+ '../src/third_party/vtune/v8vtune.gyp:v8_vtune',
+ ],
+ }],
],
},
{
diff --git a/src/date.js b/src/date.js
index c75d12c..62999e9 100644
--- a/src/date.js
+++ b/src/date.js
@@ -25,20 +25,16 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
// This file relies on the fact that the following declarations have been made
// in v8natives.js:
// var $isFinite = GlobalIsFinite;
+var $Date = global.Date;
+
// -------------------------------------------------------------------
// This file contains date support implemented in JavaScript.
-// Keep reference to original values of some global properties. This
-// has the added benefit that the code in this file is isolated from
-// changes to these properties.
-var $Date = global.Date;
-
// Helper function to throw error.
function ThrowDateTypeError() {
throw new $TypeError('this is not a Date object.');
@@ -142,7 +138,7 @@
};
-%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
+function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
if (!%_IsConstructCall()) {
// ECMA 262 - 15.9.2
return (new $Date()).toString();
@@ -199,10 +195,7 @@
value = MakeDate(day, time);
SET_LOCAL_DATE_VALUE(this, value);
}
-});
-
-
-%FunctionSetPrototype($Date, new $Date($NaN));
+}
var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
@@ -767,6 +760,10 @@
function SetUpDate() {
%CheckIsBootstrapping();
+
+ %SetCode($Date, DateConstructor);
+ %FunctionSetPrototype($Date, new $Date($NaN));
+
// Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC,
diff --git a/src/debug.cc b/src/debug.cc
index 91af9cc..4af2194 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -551,9 +551,9 @@
char* Debug::ArchiveDebug(char* storage) {
char* to = storage;
- memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+ OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
to += sizeof(ThreadLocal);
- memcpy(to, reinterpret_cast<char*>(®isters_), sizeof(registers_));
+ OS::MemCopy(to, reinterpret_cast<char*>(®isters_), sizeof(registers_));
ThreadInit();
ASSERT(to <= storage + ArchiveSpacePerThread());
return storage + ArchiveSpacePerThread();
@@ -562,9 +562,10 @@
char* Debug::RestoreDebug(char* storage) {
char* from = storage;
- memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+ OS::MemCopy(
+ reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
from += sizeof(ThreadLocal);
- memcpy(reinterpret_cast<char*>(®isters_), from, sizeof(registers_));
+ OS::MemCopy(reinterpret_cast<char*>(®isters_), from, sizeof(registers_));
ASSERT(from <= storage + ArchiveSpacePerThread());
return storage + ArchiveSpacePerThread();
}
@@ -874,8 +875,9 @@
// Check for caught exceptions.
if (caught_exception) return false;
- // Debugger loaded.
- debug_context_ = context;
+ // Debugger loaded, create debugger context global handle.
+ debug_context_ = Handle<Context>::cast(
+ isolate_->global_handles()->Create(*context));
return true;
}
@@ -891,7 +893,7 @@
DestroyScriptCache();
// Clear debugger context global handle.
- Isolate::Current()->global_handles()->Destroy(
+ isolate_->global_handles()->Destroy(
reinterpret_cast<Object**>(debug_context_.location()));
debug_context_ = Handle<Context>();
}
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 601faf7..1af7365 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -1204,6 +1204,7 @@
// and the standard stack frame slots. Include space for an argument
// object to the callee and optionally the space to pass the argument
// object to the stub failure handler.
+ ASSERT(descriptor->register_param_count_ >= 0);
int height_in_bytes = kPointerSize * descriptor->register_param_count_ +
sizeof(Arguments) + kPointerSize;
int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
@@ -2029,54 +2030,98 @@
}
-void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
- Code* check_code,
- Code* replacement_code) {
- // Iterate over the stack check table and patch every stack check
+void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ // Iterate over the back edge table and patch every interrupt
// call to an unconditional call to the replacement code.
ASSERT(unoptimized_code->kind() == Code::FUNCTION);
- ASSERT(!unoptimized_code->stack_check_patched_for_osr());
- Address stack_check_cursor = unoptimized_code->instruction_start() +
- unoptimized_code->stack_check_table_offset();
- uint32_t table_length = Memory::uint32_at(stack_check_cursor);
- stack_check_cursor += kIntSize;
+ int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
+ Address back_edge_cursor = unoptimized_code->instruction_start() +
+ unoptimized_code->back_edge_table_offset();
+ uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+ back_edge_cursor += kIntSize;
for (uint32_t i = 0; i < table_length; ++i) {
- uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
- Address pc_after = unoptimized_code->instruction_start() + pc_offset;
- PatchStackCheckCodeAt(unoptimized_code,
- pc_after,
- check_code,
- replacement_code);
- stack_check_cursor += 2 * kIntSize;
- }
- unoptimized_code->set_stack_check_patched_for_osr(true);
-}
-
-
-void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
- Code* check_code,
- Code* replacement_code) {
- // Iterate over the stack check table and revert the patched
- // stack check calls.
- ASSERT(unoptimized_code->kind() == Code::FUNCTION);
- ASSERT(unoptimized_code->stack_check_patched_for_osr());
- Address stack_check_cursor = unoptimized_code->instruction_start() +
- unoptimized_code->stack_check_table_offset();
- uint32_t table_length = Memory::uint32_at(stack_check_cursor);
- stack_check_cursor += kIntSize;
- for (uint32_t i = 0; i < table_length; ++i) {
- uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
- Address pc_after = unoptimized_code->instruction_start() + pc_offset;
- RevertStackCheckCodeAt(unoptimized_code,
+ uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+ if (loop_depth == loop_nesting_level) {
+ // Loop back edge has the loop depth that we want to patch.
+ uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+ Address pc_after = unoptimized_code->instruction_start() + pc_offset;
+ PatchInterruptCodeAt(unoptimized_code,
pc_after,
- check_code,
+ interrupt_code,
replacement_code);
- stack_check_cursor += 2 * kIntSize;
+ }
+ back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
- unoptimized_code->set_stack_check_patched_for_osr(false);
+ unoptimized_code->set_back_edges_patched_for_osr(true);
+#ifdef DEBUG
+ Deoptimizer::VerifyInterruptCode(
+ unoptimized_code, interrupt_code, replacement_code, loop_nesting_level);
+#endif // DEBUG
}
+void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ // Iterate over the back edge table and revert the patched interrupt calls.
+ ASSERT(unoptimized_code->kind() == Code::FUNCTION);
+ ASSERT(unoptimized_code->back_edges_patched_for_osr());
+ int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
+ Address back_edge_cursor = unoptimized_code->instruction_start() +
+ unoptimized_code->back_edge_table_offset();
+ uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+ back_edge_cursor += kIntSize;
+ for (uint32_t i = 0; i < table_length; ++i) {
+ uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+ if (loop_depth <= loop_nesting_level) {
+ uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+ Address pc_after = unoptimized_code->instruction_start() + pc_offset;
+ RevertInterruptCodeAt(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code);
+ }
+ back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
+ }
+ unoptimized_code->set_back_edges_patched_for_osr(false);
+#ifdef DEBUG
+ // Assert that none of the back edges are patched anymore.
+ Deoptimizer::VerifyInterruptCode(
+ unoptimized_code, interrupt_code, replacement_code, -1);
+#endif // DEBUG
+}
+
+
+#ifdef DEBUG
+void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code,
+ Code* interrupt_code,
+ Code* replacement_code,
+ int loop_nesting_level) {
+ CHECK(unoptimized_code->kind() == Code::FUNCTION);
+ Address back_edge_cursor = unoptimized_code->instruction_start() +
+ unoptimized_code->back_edge_table_offset();
+ uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+ back_edge_cursor += kIntSize;
+ for (uint32_t i = 0; i < table_length; ++i) {
+ uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+ CHECK_LE(loop_depth, Code::kMaxLoopNestingMarker);
+ // Assert that all back edges for shallower loops (and only those)
+ // have already been patched.
+ uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+ Address pc_after = unoptimized_code->instruction_start() + pc_offset;
+ CHECK_EQ((loop_depth <= loop_nesting_level),
+ InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
+ }
+}
+#endif // DEBUG
+
+
unsigned Deoptimizer::ComputeInputFrameSize() const {
unsigned fixed_size = ComputeFixedSize(function_);
// The fp-to-sp delta already takes the context and the function
@@ -2327,7 +2372,8 @@
Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
int length = contents_.length();
Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
- memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
+ OS::MemCopy(
+ result->GetDataStartAddress(), contents_.ToVector().start(), length);
return result;
}
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 895ed66..97b2206 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -210,32 +210,45 @@
// The size in bytes of the code required at a lazy deopt patch site.
static int patch_size();
- // Patch all stack guard checks in the unoptimized code to
+ // Patch all interrupts with allowed loop depth in the unoptimized code to
// unconditionally call replacement_code.
- static void PatchStackCheckCode(Code* unoptimized_code,
- Code* check_code,
- Code* replacement_code);
+ static void PatchInterruptCode(Code* unoptimized_code,
+ Code* interrupt_code,
+ Code* replacement_code);
- // Patch stack guard check at instruction before pc_after in
+ // Patch the interrupt at the instruction before pc_after in
// the unoptimized code to unconditionally call replacement_code.
- static void PatchStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code);
-
- // Change all patched stack guard checks in the unoptimized code
- // back to a normal stack guard check.
- static void RevertStackCheckCode(Code* unoptimized_code,
- Code* check_code,
+ static void PatchInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
Code* replacement_code);
- // Change all patched stack guard checks in the unoptimized code
- // back to a normal stack guard check.
- static void RevertStackCheckCodeAt(Code* unoptimized_code,
+ // Change all patched interrupts patched in the unoptimized code
+ // back to normal interrupts.
+ static void RevertInterruptCode(Code* unoptimized_code,
+ Code* interrupt_code,
+ Code* replacement_code);
+
+ // Change patched interrupt in the unoptimized code
+ // back to a normal interrupt.
+ static void RevertInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code);
+
+#ifdef DEBUG
+ static bool InterruptCodeIsPatched(Code* unoptimized_code,
Address pc_after,
- Code* check_code,
+ Code* interrupt_code,
Code* replacement_code);
+ // Verify that all back edges of a certain loop depth are patched.
+ static void VerifyInterruptCode(Code* unoptimized_code,
+ Code* interrupt_code,
+ Code* replacement_code,
+ int loop_nesting_level);
+#endif // DEBUG
+
~Deoptimizer();
void MaterializeHeapObjects(JavaScriptFrameIterator* it);
diff --git a/src/disassembler.cc b/src/disassembler.cc
index f168f84..b01b443 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -50,8 +50,8 @@
pc - begin,
*pc);
} else {
- fprintf(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
- reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
+ PrintF(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
+ reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
}
}
}
@@ -101,13 +101,12 @@
if (f == NULL) {
PrintF("%s\n", out->Finalize());
} else {
- fprintf(f, "%s\n", out->Finalize());
+ PrintF(f, "%s\n", out->Finalize());
}
out->Reset();
}
-
static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
static const int kRelocInfoPosition = 57;
@@ -337,10 +336,10 @@
code->kind() == Code::COMPILED_STUB)
? static_cast<int>(code->safepoint_table_offset())
: code->instruction_size();
- // If there might be a stack check table, stop before reaching it.
+ // If there might be a back edge table, stop before reaching it.
if (code->kind() == Code::FUNCTION) {
decode_size =
- Min(decode_size, static_cast<int>(code->stack_check_table_offset()));
+ Min(decode_size, static_cast<int>(code->back_edge_table_offset()));
}
byte* begin = code->instruction_start();
diff --git a/src/elements.cc b/src/elements.cc
index 9deef60..7c2b568 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -183,7 +183,7 @@
Address from_address = from->address() + FixedArray::kHeaderSize;
CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
reinterpret_cast<Object**>(from_address) + from_start,
- copy_size);
+ static_cast<size_t>(copy_size));
if (IsFastObjectElementsKind(from_kind) &&
IsFastObjectElementsKind(to_kind)) {
Heap* heap = from->GetHeap();
@@ -339,7 +339,7 @@
int words_per_double = (kDoubleSize / kPointerSize);
CopyWords(reinterpret_cast<Object**>(to_address),
reinterpret_cast<Object**>(from_address),
- words_per_double * copy_size);
+ static_cast<size_t>(words_per_double * copy_size));
}
diff --git a/src/execution.cc b/src/execution.cc
index dee3112..025a256 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -33,6 +33,7 @@
#include "bootstrapper.h"
#include "codegen.h"
#include "debug.h"
+#include "deoptimizer.h"
#include "isolate-inl.h"
#include "runtime-profiler.h"
#include "simulator.h"
@@ -448,6 +449,19 @@
}
+bool StackGuard::IsFullDeopt() {
+ ExecutionAccess access(isolate_);
+ return (thread_local_.interrupt_flags_ & FULL_DEOPT) != 0;
+}
+
+
+void StackGuard::FullDeopt() {
+ ExecutionAccess access(isolate_);
+ thread_local_.interrupt_flags_ |= FULL_DEOPT;
+ set_interrupt_limits(access);
+}
+
+
#ifdef ENABLE_DEBUGGER_SUPPORT
bool StackGuard::IsDebugBreak() {
ExecutionAccess access(isolate_);
@@ -488,7 +502,7 @@
char* StackGuard::ArchiveStackGuard(char* to) {
ExecutionAccess access(isolate_);
- memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+ OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
ThreadLocal blank;
// Set the stack limits using the old thread_local_.
@@ -505,7 +519,8 @@
char* StackGuard::RestoreStackGuard(char* from) {
ExecutionAccess access(isolate_);
- memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+ OS::MemCopy(
+ reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
isolate_->heap()->SetStackLimits();
return from + sizeof(ThreadLocal);
}
@@ -880,7 +895,6 @@
stack_guard->Continue(GC_REQUEST);
}
-
isolate->counters()->stack_interrupts()->Increment();
isolate->counters()->runtime_profiler_ticks()->Increment();
isolate->runtime_profiler()->OptimizeNow();
@@ -898,6 +912,10 @@
stack_guard->Continue(INTERRUPT);
return isolate->StackOverflow();
}
+ if (stack_guard->IsFullDeopt()) {
+ stack_guard->Continue(FULL_DEOPT);
+ Deoptimizer::DeoptimizeAll(isolate);
+ }
return isolate->heap()->undefined_value();
}
diff --git a/src/execution.h b/src/execution.h
index b104180..9cf8ac6 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -41,7 +41,8 @@
DEBUGCOMMAND = 1 << 2,
PREEMPT = 1 << 3,
TERMINATE = 1 << 4,
- GC_REQUEST = 1 << 5
+ GC_REQUEST = 1 << 5,
+ FULL_DEOPT = 1 << 6
};
@@ -197,6 +198,8 @@
#endif
bool IsGCRequest();
void RequestGC();
+ bool IsFullDeopt();
+ void FullDeopt();
void Continue(InterruptFlag after_what);
// This provides an asynchronous read of the stack limits for the current
diff --git a/src/factory.cc b/src/factory.cc
index fece9a0..5e2a2b1 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -578,15 +578,22 @@
}
+static Handle<Map> MapForNewFunction(Isolate *isolate,
+ Handle<SharedFunctionInfo> function_info) {
+ Context *context = isolate->context()->native_context();
+ int map_index = Context::FunctionMapIndex(function_info->language_mode(),
+ function_info->is_generator());
+ return Handle<Map>(Map::cast(context->get(map_index)));
+}
+
+
Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Context> context,
PretenureFlag pretenure) {
Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
function_info,
- function_info->is_classic_mode()
- ? isolate()->function_map()
- : isolate()->strict_mode_function_map(),
+ MapForNewFunction(isolate(), function_info),
pretenure);
if (function_info->ic_age() != isolate()->heap()->global_ic_age()) {
@@ -874,14 +881,7 @@
initial_map->set_constructor(*function);
}
- // Set function.prototype and give the prototype a constructor
- // property that refers to the function.
SetPrototypeProperty(function, prototype);
- // Currently safe because it is only invoked from Genesis.
- CHECK_NOT_EMPTY_HANDLE(isolate(),
- JSObject::SetLocalPropertyIgnoreAttributes(
- prototype, constructor_string(),
- function, DONT_ENUM));
return function;
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index ea72168..9c9362b 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -119,6 +119,22 @@
};
#endif
+#if (defined CAN_USE_VFP3_INSTRUCTIONS) || !(defined ARM_TEST)
+# define ENABLE_VFP3_DEFAULT true
+#else
+# define ENABLE_VFP3_DEFAULT false
+#endif
+#if (defined CAN_USE_ARMV7_INSTRUCTIONS) || !(defined ARM_TEST)
+# define ENABLE_ARMV7_DEFAULT true
+#else
+# define ENABLE_ARMV7_DEFAULT false
+#endif
+#if (defined CAN_USE_VFP32DREGS) || !(defined ARM_TEST)
+# define ENABLE_32DREGS_DEFAULT true
+#else
+# define ENABLE_32DREGS_DEFAULT false
+#endif
+
#define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
#define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
#define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
@@ -168,12 +184,12 @@
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
DEFINE_bool(compiled_transitions, false, "use optimizing compiler to "
"generate array elements transition stubs")
-DEFINE_bool(compiled_keyed_stores, false, "use optimizing compiler to "
+DEFINE_bool(compiled_keyed_stores, true, "use optimizing compiler to "
"generate keyed store stubs")
DEFINE_bool(clever_optimizations,
true,
"Optimize object size, Array shift, DOM strings and string +")
-DEFINE_bool(pretenure_literals, false, "allocate literals in old space")
+DEFINE_bool(pretenure_literals, true, "allocate literals in old space")
// Flags for data representation optimizations
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
@@ -308,12 +324,9 @@
"enable use of RDTSC instruction if available")
DEFINE_bool(enable_sahf, true,
"enable use of SAHF instruction if available (X64 only)")
-DEFINE_bool(enable_vfp3, true,
- "enable use of VFP3 instructions if available - this implies "
- "enabling ARMv7 and VFP2 instructions (ARM only)")
-DEFINE_bool(enable_vfp2, true,
- "enable use of VFP2 instructions if available")
-DEFINE_bool(enable_armv7, true,
+DEFINE_bool(enable_vfp3, ENABLE_VFP3_DEFAULT,
+ "enable use of VFP3 instructions if available")
+DEFINE_bool(enable_armv7, ENABLE_ARMV7_DEFAULT,
"enable use of ARMv7 instructions if available (ARM only)")
DEFINE_bool(enable_sudiv, true,
"enable use of SDIV and UDIV instructions if available (ARM only)")
@@ -322,10 +335,8 @@
"instruction pairs (ARM only)")
DEFINE_bool(enable_unaligned_accesses, true,
"enable unaligned accesses for ARMv7 (ARM only)")
-DEFINE_bool(enable_32dregs, true,
+DEFINE_bool(enable_32dregs, ENABLE_32DREGS_DEFAULT,
"enable use of d16-d31 registers on ARM - this requires VFP3")
-DEFINE_bool(enable_fpu, true,
- "enable use of MIPS FPU instructions if available (MIPS only)")
DEFINE_bool(enable_vldr_imm, false,
"enable use of constant pools for double immediate (ARM only)")
@@ -502,6 +513,8 @@
"Stack alingment in bytes in simulator (4 or 8, 8 is default)")
// isolate.cc
+DEFINE_bool(abort_on_uncaught_exception, false,
+ "abort program (dump core) when an uncaught exception is thrown")
DEFINE_bool(trace_exception, false,
"print stack trace when throwing exceptions")
DEFINE_bool(preallocate_message_memory, false,
diff --git a/src/flags.cc b/src/flags.cc
index ff725ad..282bf20 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -34,6 +34,9 @@
#include "smart-pointers.h"
#include "string-stream.h"
+#ifdef V8_TARGET_ARCH_ARM
+#include "arm/assembler-arm-inl.h"
+#endif
namespace v8 {
namespace internal {
@@ -305,7 +308,7 @@
// make a copy so we can NUL-terminate flag name
size_t n = arg - *name;
CHECK(n < static_cast<size_t>(buffer_size)); // buffer is too small
- memcpy(buffer, *name, n);
+ OS::MemCopy(buffer, *name, n);
buffer[n] = '\0';
*name = buffer;
// get the value
@@ -367,8 +370,8 @@
// sense there.
continue;
} else {
- fprintf(stderr, "Error: unrecognized flag %s\n"
- "Try --help for options\n", arg);
+ PrintF(stderr, "Error: unrecognized flag %s\n"
+ "Try --help for options\n", arg);
return_code = j;
break;
}
@@ -381,9 +384,9 @@
if (i < *argc) {
value = argv[i++];
} else {
- fprintf(stderr, "Error: missing value for flag %s of type %s\n"
- "Try --help for options\n",
- arg, Type2String(flag->type()));
+ PrintF(stderr, "Error: missing value for flag %s of type %s\n"
+ "Try --help for options\n",
+ arg, Type2String(flag->type()));
return_code = j;
break;
}
@@ -424,9 +427,9 @@
if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
(flag->type() != Flag::TYPE_BOOL && is_bool) ||
*endp != '\0') {
- fprintf(stderr, "Error: illegal value for flag %s of type %s\n"
- "Try --help for options\n",
- arg, Type2String(flag->type()));
+ PrintF(stderr, "Error: illegal value for flag %s of type %s\n"
+ "Try --help for options\n",
+ arg, Type2String(flag->type()));
return_code = j;
break;
}
@@ -475,7 +478,7 @@
int FlagList::SetFlagsFromString(const char* str, int len) {
// make a 0-terminated copy of str
ScopedVector<char> copy0(len + 1);
- memcpy(copy0.start(), str, len);
+ OS::MemCopy(copy0.start(), str, len);
copy0[len] = '\0';
// strip leading white space
@@ -517,6 +520,12 @@
// static
void FlagList::PrintHelp() {
+#ifdef V8_TARGET_ARCH_ARM
+ CpuFeatures::PrintTarget();
+ CpuFeatures::Probe();
+ CpuFeatures::PrintFeatures();
+#endif // V8_TARGET_ARCH_ARM
+
printf("Usage:\n");
printf(" shell [options] -e string\n");
printf(" execute string in V8\n");
diff --git a/src/frames.h b/src/frames.h
index ca0d5be..11e8d28 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -84,6 +84,18 @@
};
+class StackHandlerConstants : public AllStatic {
+ public:
+ static const int kNextOffset = 0 * kPointerSize;
+ static const int kCodeOffset = 1 * kPointerSize;
+ static const int kStateOffset = 2 * kPointerSize;
+ static const int kContextOffset = 3 * kPointerSize;
+ static const int kFPOffset = 4 * kPointerSize;
+
+ static const int kSize = kFPOffset + kPointerSize;
+};
+
+
class StackHandler BASE_EMBEDDED {
public:
enum Kind {
@@ -581,7 +593,6 @@
inline Object* function_slot_object() const;
friend class StackFrameIterator;
- friend class StackTracer;
};
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 1c6a0b9..72d0835 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -322,7 +322,7 @@
ASSERT(!isolate->has_pending_exception());
return false;
}
- unsigned table_offset = cgen.EmitStackCheckTable();
+ unsigned table_offset = cgen.EmitBackEdgeTable();
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
@@ -341,8 +341,8 @@
#endif // ENABLE_DEBUGGER_SUPPORT
code->set_allow_osr_at_loop_nesting_level(0);
code->set_profiler_ticks(0);
- code->set_stack_check_table_offset(table_offset);
- code->set_stack_check_patched_for_osr(false);
+ code->set_back_edge_table_offset(table_offset);
+ code->set_back_edges_patched_for_osr(false);
CodeGenerator::PrintCode(code, info);
info->SetCode(code); // May be an empty handle.
#ifdef ENABLE_GDB_JIT_INTERFACE
@@ -362,17 +362,18 @@
}
-unsigned FullCodeGenerator::EmitStackCheckTable() {
- // The stack check table consists of a length (in number of entries)
+unsigned FullCodeGenerator::EmitBackEdgeTable() {
+ // The back edge table consists of a length (in number of entries)
// field, and then a sequence of entries. Each entry is a pair of AST id
// and code-relative pc offset.
masm()->Align(kIntSize);
unsigned offset = masm()->pc_offset();
- unsigned length = stack_checks_.length();
+ unsigned length = back_edges_.length();
__ dd(length);
for (unsigned i = 0; i < length; ++i) {
- __ dd(stack_checks_[i].id.ToInt());
- __ dd(stack_checks_[i].pc_and_state);
+ __ dd(back_edges_[i].id.ToInt());
+ __ dd(back_edges_[i].pc);
+ __ db(back_edges_[i].loop_depth);
}
return offset;
}
@@ -478,8 +479,11 @@
void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) {
// The pc offset does not need to be encoded and packed together with a state.
ASSERT(masm_->pc_offset() > 0);
- BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) };
- stack_checks_.Add(entry, zone());
+ ASSERT(loop_depth() > 0);
+ uint8_t depth = Min(loop_depth(), Code::kMaxLoopNestingMarker);
+ BackEdgeEntry entry =
+ { ast_id, static_cast<unsigned>(masm_->pc_offset()), depth };
+ back_edges_.Add(entry, zone());
}
@@ -1251,7 +1255,7 @@
void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement");
SetStatementPosition(stmt);
- Label body, stack_check;
+ Label body, book_keeping;
Iteration loop_statement(this, stmt);
increment_loop_depth();
@@ -1265,13 +1269,13 @@
PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
SetExpressionPosition(stmt->cond(), stmt->condition_position());
VisitForControl(stmt->cond(),
- &stack_check,
+ &book_keeping,
loop_statement.break_label(),
- &stack_check);
+ &book_keeping);
// Check stack before looping.
PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
- __ bind(&stack_check);
+ __ bind(&book_keeping);
EmitBackEdgeBookkeeping(stmt, &body);
__ jmp(&body);
@@ -1549,6 +1553,8 @@
UNIMPLEMENTED();
Comment cmnt(masm_, "[ Yield");
+ // TODO(wingo): Actually update the iterator state.
+ VisitForEffect(expr->generator_object());
VisitForAccumulatorValue(expr->expression());
// TODO(wingo): Assert that the operand stack depth is 0, at least while
// general yield expressions are unimplemented.
diff --git a/src/full-codegen.h b/src/full-codegen.h
index c4f3fcc..b9647c2 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -92,7 +92,7 @@
bailout_entries_(info->HasDeoptimizationSupport()
? info->function()->ast_node_count() : 0,
info->zone()),
- stack_checks_(2, info->zone()), // There's always at least one.
+ back_edges_(2, info->zone()),
type_feedback_cells_(info->HasDeoptimizationSupport()
? info->function()->ast_node_count() : 0,
info->zone()),
@@ -135,6 +135,7 @@
#error Unsupported target architecture.
#endif
+ static const int kBackEdgeEntrySize = 2 * kIntSize + kOneByteSize;
private:
class Breakable;
@@ -459,9 +460,9 @@
Label* back_edge_target);
// Record the OSR AST id corresponding to a back edge in the code.
void RecordBackEdge(BailoutId osr_ast_id);
- // Emit a table of stack check ids and pcs into the code stream. Return
- // the offset of the start of the table.
- unsigned EmitStackCheckTable();
+ // Emit a table of back edge ids, pcs and loop depths into the code stream.
+ // Return the offset of the start of the table.
+ unsigned EmitBackEdgeTable();
void EmitProfilingCounterDecrement(int delta);
void EmitProfilingCounterReset();
@@ -624,6 +625,12 @@
unsigned pc_and_state;
};
+ struct BackEdgeEntry {
+ BailoutId id;
+ unsigned pc;
+ uint8_t loop_depth;
+ };
+
struct TypeFeedbackCellEntry {
TypeFeedbackId ast_id;
Handle<JSGlobalPropertyCell> cell;
@@ -818,9 +825,7 @@
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
GrowableBitVector prepared_bailout_ids_;
- // TODO(svenpanne) Rename this to something like back_edges_ and rename
- // related functions accordingly.
- ZoneList<BailoutEntry> stack_checks_;
+ ZoneList<BackEdgeEntry> back_edges_;
ZoneList<TypeFeedbackCellEntry> type_feedback_cells_;
int ic_total_count_;
Handle<FixedArray> handler_table_;
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index cf8ca2d..d08f2fe 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -629,7 +629,7 @@
#if defined(__ELF)
class ELF BASE_EMBEDDED {
public:
- ELF(Zone* zone) : sections_(6, zone) {
+ explicit ELF(Zone* zone) : sections_(6, zone) {
sections_.Add(new(zone) ELFSection("", ELFSection::TYPE_NULL, 0), zone);
sections_.Add(new(zone) ELFStringTable(".shstrtab"), zone);
}
@@ -681,7 +681,7 @@
#else
#error Unsupported target architecture.
#endif
- memcpy(header->ident, ident, 16);
+ OS::MemCopy(header->ident, ident, 16);
header->type = 1;
#if defined(V8_TARGET_ARCH_IA32)
header->machine = 3;
@@ -1019,9 +1019,9 @@
#if defined(__ELF)
static void CreateSymbolsTable(CodeDescription* desc,
+ Zone* zone,
ELF* elf,
int text_section_index) {
- Zone* zone = desc->info()->zone();
ELFSymbolTable* symtab = new(zone) ELFSymbolTable(".symtab", zone);
ELFStringTable* strtab = new(zone) ELFStringTable(".strtab");
@@ -1213,8 +1213,11 @@
w->WriteSLEB128(StandardFrameConstants::kContextOffset);
block_size.set(static_cast<uint32_t>(w->position() - block_start));
}
+
+ w->WriteULEB128(0); // Terminate the sub program.
}
+ w->WriteULEB128(0); // Terminate the compile unit.
size.set(static_cast<uint32_t>(w->position() - start));
return true;
}
@@ -1324,15 +1327,14 @@
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
int locals = scope->StackLocalCount();
- int total_children =
- params + slots + context_slots + internal_slots + locals + 2;
+ // Total children is params + slots + context_slots + internal_slots +
+ // locals + 2 (__function and __context).
// The extra duplication below seems to be necessary to keep
// gdb from getting upset on OSX.
w->WriteULEB128(current_abbreviation++); // Abbreviation code.
w->WriteULEB128(DW_TAG_SUBPROGRAM);
- w->Write<uint8_t>(
- total_children != 0 ? DW_CHILDREN_YES : DW_CHILDREN_NO);
+ w->Write<uint8_t>(DW_CHILDREN_YES);
w->WriteULEB128(DW_AT_NAME);
w->WriteULEB128(DW_FORM_STRING);
w->WriteULEB128(DW_AT_LOW_PC);
@@ -1384,9 +1386,7 @@
// The context.
WriteVariableAbbreviation(w, current_abbreviation++, true, false);
- if (total_children != 0) {
- w->WriteULEB128(0); // Terminate the sibling list.
- }
+ w->WriteULEB128(0); // Terminate the sibling list.
}
w->WriteULEB128(0); // Terminate the table.
@@ -1789,8 +1789,9 @@
#endif // V8_TARGET_ARCH_X64
-static void CreateDWARFSections(CodeDescription* desc, DebugObject* obj) {
- Zone* zone = desc->info()->zone();
+static void CreateDWARFSections(CodeDescription* desc,
+ Zone* zone,
+ DebugObject* obj) {
if (desc->IsLineInfoAvailable()) {
obj->AddSection(new(zone) DebugInfoSection(desc), zone);
obj->AddSection(new(zone) DebugAbbrevSection(desc), zone);
@@ -1841,7 +1842,7 @@
#ifdef OBJECT_PRINT
void __gdb_print_v8_object(MaybeObject* object) {
object->Print();
- fprintf(stdout, "\n");
+ PrintF(stdout, "\n");
}
#endif
}
@@ -1854,7 +1855,7 @@
entry->symfile_addr_ = reinterpret_cast<Address>(entry + 1);
entry->symfile_size_ = symfile_size;
- memcpy(entry->symfile_addr_, symfile_addr, symfile_size);
+ OS::MemCopy(entry->symfile_addr_, symfile_addr, symfile_size);
entry->prev_ = entry->next_ = NULL;
@@ -1915,8 +1916,7 @@
}
-static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
- Zone* zone = desc->info()->zone();
+static JITCodeEntry* CreateELFObject(CodeDescription* desc, Zone* zone) {
ZoneScope zone_scope(zone, DELETE_ON_EXIT);
#ifdef __MACH_O
MachO mach_o;
@@ -1944,9 +1944,9 @@
ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC),
zone);
- CreateSymbolsTable(desc, &elf, text_section_index);
+ CreateSymbolsTable(desc, zone, &elf, text_section_index);
- CreateDWARFSections(desc, &elf);
+ CreateDWARFSections(desc, zone, &elf);
elf.Write(&w);
#endif
@@ -2083,7 +2083,8 @@
}
AddUnwindInfo(&code_desc);
- JITCodeEntry* entry = CreateELFObject(&code_desc);
+ Zone* zone = code->GetIsolate()->runtime_zone();
+ JITCodeEntry* entry = CreateELFObject(&code_desc, zone);
ASSERT(!IsLineInfoTagged(entry));
delete lineinfo;
diff --git a/src/generator.js b/src/generator.js
new file mode 100644
index 0000000..d579928
--- /dev/null
+++ b/src/generator.js
@@ -0,0 +1,74 @@
+// Copyright 2013 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.
+
+"use strict";
+
+// This file relies on the fact that the following declarations have been made
+// in runtime.js:
+// var $Function = global.Function;
+
+// ----------------------------------------------------------------------------
+
+
+// TODO(wingo): Give link to specification. For now, the following diagram is
+// the spec:
+// http://wiki.ecmascript.org/lib/exe/fetch.php?cache=cache&media=harmony:es6_generator_object_model_3-29-13.png
+
+function GeneratorObjectNext() {
+ // TODO(wingo): Implement.
+}
+
+function GeneratorObjectSend(value) {
+ // TODO(wingo): Implement.
+}
+
+function GeneratorObjectThrow(exn) {
+ // TODO(wingo): Implement.
+}
+
+function GeneratorObjectClose() {
+ // TODO(wingo): Implement.
+}
+
+function SetUpGenerators() {
+ %CheckIsBootstrapping();
+ var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
+ InstallFunctions(GeneratorObjectPrototype,
+ DONT_ENUM | DONT_DELETE | READ_ONLY,
+ ["next", GeneratorObjectNext,
+ "send", GeneratorObjectSend,
+ "throw", GeneratorObjectThrow,
+ "close", GeneratorObjectClose]);
+ %SetProperty(GeneratorObjectPrototype, "constructor",
+ GeneratorFunctionPrototype, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetPrototype(GeneratorFunctionPrototype, $Function.prototype);
+ %SetProperty(GeneratorFunctionPrototype, "constructor",
+ GeneratorFunction, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetPrototype(GeneratorFunction, $Function);
+}
+
+SetUpGenerators();
diff --git a/src/global-handles.h b/src/global-handles.h
index 9900144..90707b0 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -31,10 +31,15 @@
#include "../include/v8-profiler.h"
#include "list.h"
+#include "v8utils.h"
namespace v8 {
namespace internal {
+class GCTracer;
+class HeapStats;
+class ObjectVisitor;
+
// Structure for tracking global handles.
// A single list keeps all the allocated global handles.
// Destroyed handles stay in the list but is added to the free list.
@@ -88,7 +93,7 @@
malloc(OFFSET_OF(ImplicitRefGroup, children_[length])));
group->parent_ = parent;
group->length_ = length;
- CopyWords(group->children_, children, static_cast<int>(length));
+ CopyWords(group->children_, children, length);
return group;
}
diff --git a/src/globals.h b/src/globals.h
index 1606996..59931bf 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -67,9 +67,21 @@
// http://www.agner.org/optimize/calling_conventions.pdf
// or with gcc, run: "echo | gcc -E -dM -"
#if defined(_M_X64) || defined(__x86_64__)
+#if defined(__native_client__)
+// For Native Client builds of V8, use V8_TARGET_ARCH_ARM, so that V8
+// generates ARM machine code, together with a portable ARM simulator
+// compiled for the host architecture in question.
+//
+// Since Native Client is ILP-32 on all architectures we use
+// V8_HOST_ARCH_IA32 on both 32- and 64-bit x86.
+#define V8_HOST_ARCH_IA32 1
+#define V8_HOST_ARCH_32_BIT 1
+#define V8_HOST_CAN_READ_UNALIGNED 1
+#else
#define V8_HOST_ARCH_X64 1
#define V8_HOST_ARCH_64_BIT 1
#define V8_HOST_CAN_READ_UNALIGNED 1
+#endif // __native_client__
#elif defined(_M_IX86) || defined(__i386__)
#define V8_HOST_ARCH_IA32 1
#define V8_HOST_ARCH_32_BIT 1
diff --git a/src/handles-inl.h b/src/handles-inl.h
index b763c86..bb11311 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -59,7 +59,6 @@
if (FLAG_enable_slow_asserts) {
Isolate* isolate = Isolate::Current();
CHECK(isolate->AllowHandleDereference() ||
- Heap::RelocationLock::IsLocked(isolate->heap()) ||
!isolate->optimizing_compiler_thread()->IsOptimizerThread());
}
#endif // DEBUG
diff --git a/src/handles.cc b/src/handles.cc
index b24a4cd..059ff24 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -252,15 +252,32 @@
}
+Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key) {
+ Isolate* isolate = object->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ Runtime::DeleteObjectProperty(
+ isolate, object, key, JSReceiver::NORMAL_DELETION),
+ Object);
+}
+
+
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key) {
Isolate* isolate = object->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
- Runtime::ForceDeleteObjectProperty(isolate, object, key),
+ Runtime::DeleteObjectProperty(
+ isolate, object, key, JSReceiver::FORCE_DELETION),
Object);
}
+Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key) {
+ Isolate* isolate = obj->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ Runtime::HasObjectProperty(isolate, obj, key), Object);
+}
+
+
Handle<Object> GetProperty(Handle<JSReceiver> obj,
const char* name) {
Isolate* isolate = obj->GetIsolate();
@@ -308,6 +325,14 @@
}
+Handle<JSObject> DeepCopy(Handle<JSObject> obj) {
+ Isolate* isolate = obj->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ obj->DeepCopy(isolate),
+ JSObject);
+}
+
+
Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
}
diff --git a/src/handles.h b/src/handles.h
index c69713e..8e9404c 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -223,11 +223,13 @@
Handle<Object> value,
PropertyAttributes attributes);
-Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
- Handle<Object> key);
+Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key);
-Handle<Object> GetProperty(Handle<JSReceiver> obj,
- const char* name);
+Handle<Object> ForceDeleteProperty(Handle<JSObject> object, Handle<Object> key);
+
+Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key);
+
+Handle<Object> GetProperty(Handle<JSReceiver> obj, const char* name);
Handle<Object> GetProperty(Isolate* isolate,
Handle<Object> obj,
@@ -240,6 +242,8 @@
Handle<JSObject> Copy(Handle<JSObject> obj);
+Handle<JSObject> DeepCopy(Handle<JSObject> obj);
+
Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info);
Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray>,
diff --git a/src/heap-inl.h b/src/heap-inl.h
index a15b8ef..28e50aa 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -159,8 +159,8 @@
ASSERT_EQ(size, answer->Size());
// Fill in the characters.
- memcpy(answer->address() + SeqOneByteString::kHeaderSize,
- str.start(), str.length());
+ OS::MemCopy(answer->address() + SeqOneByteString::kHeaderSize,
+ str.start(), str.length());
return answer;
}
@@ -192,8 +192,8 @@
ASSERT_EQ(size, answer->Size());
// Fill in the characters.
- memcpy(answer->address() + SeqTwoByteString::kHeaderSize,
- str.start(), str.length() * kUC16Size);
+ OS::MemCopy(answer->address() + SeqTwoByteString::kHeaderSize,
+ str.start(), str.length() * kUC16Size);
return answer;
}
@@ -345,6 +345,16 @@
}
+bool Heap::InOldDataSpace(Address address) {
+ return old_data_space_->Contains(address);
+}
+
+
+bool Heap::InOldDataSpace(Object* object) {
+ return InOldDataSpace(reinterpret_cast<Address>(object));
+}
+
+
bool Heap::OldGenerationAllocationLimitReached() {
if (!incremental_marking()->IsStopped()) return false;
return OldGenerationSpaceAvailable() < 0;
@@ -417,7 +427,7 @@
void Heap::CopyBlock(Address dst, Address src, int byte_size) {
CopyWords(reinterpret_cast<Object**>(dst),
reinterpret_cast<Object**>(src),
- byte_size / kPointerSize);
+ static_cast<size_t>(byte_size / kPointerSize));
}
@@ -435,7 +445,7 @@
*dst_slot++ = *src_slot++;
}
} else {
- memmove(dst, src, byte_size);
+ OS::MemMove(dst, src, static_cast<size_t>(byte_size));
}
}
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index fb239aa..d22239f 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -2319,7 +2319,7 @@
int s_chunk_size = Min(
chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
ASSERT(s_chunk_size > 0);
- memcpy(chunk_.start() + chunk_pos_, s, s_chunk_size);
+ OS::MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
s += s_chunk_size;
chunk_pos_ += s_chunk_size;
MaybeWriteChunk();
diff --git a/src/heap.cc b/src/heap.cc
index fafcb64..453d985 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -162,8 +162,7 @@
#endif
promotion_queue_(this),
configured_(false),
- chunks_queued_for_free_(NULL),
- relocation_mutex_(NULL) {
+ chunks_queued_for_free_(NULL) {
// Allow build-time customization of the max semispace size. Building
// V8 with snapshots and a non-default max semispace size is much
// easier if you can define it as part of the build environment.
@@ -688,9 +687,9 @@
ASSERT(array->map() != HEAP->fixed_cow_array_map());
Object** dst_objects = array->data_start() + dst_index;
- memmove(dst_objects,
- array->data_start() + src_index,
- len * kPointerSize);
+ OS::MemMove(dst_objects,
+ array->data_start() + src_index,
+ len * kPointerSize);
if (!InNewSpace(array)) {
for (int i = 0; i < len; i++) {
// TODO(hpayer): check store buffer for entries
@@ -952,6 +951,13 @@
PrintPID("Limited new space size due to high promotion rate: %d MB\n",
new_space_.InitialCapacity() / MB);
}
+ // Support for global pre-tenuring uses the high promotion mode as a
+ // heuristic indicator of whether to pretenure or not, we trigger
+ // deoptimization here to take advantage of pre-tenuring as soon as
+ // possible.
+ if (FLAG_pretenure_literals) {
+ isolate_->stack_guard()->FullDeopt();
+ }
} else if (new_space_high_promotion_mode_active_ &&
IsStableOrDecreasingSurvivalTrend() &&
IsLowSurvivalRate()) {
@@ -963,6 +969,11 @@
PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
new_space_.MaximumCapacity() / MB);
}
+ // Trigger deoptimization here to turn off pre-tenuring as soon as
+ // possible.
+ if (FLAG_pretenure_literals) {
+ isolate_->stack_guard()->FullDeopt();
+ }
}
if (new_space_high_promotion_mode_active_ &&
@@ -1282,8 +1293,6 @@
void Heap::Scavenge() {
- RelocationLock relocation_lock(this);
-
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
#endif
@@ -2836,13 +2845,6 @@
}
hidden_string_ = String::cast(obj);
- // Allocate the foreign for __proto__.
- { MaybeObject* maybe_obj =
- AllocateForeign((Address) &Accessors::ObjectPrototype);
- if (!maybe_obj->ToObject(&obj)) return false;
- }
- set_prototype_accessors(Foreign::cast(obj));
-
// Allocate the code_stubs dictionary. The initial size is set to avoid
// expanding the dictionary during bootstrapping.
{ MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(this, 128);
@@ -3963,30 +3965,36 @@
MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
- // Allocate the prototype. Make sure to use the object function
- // from the function's context, since the function can be from a
- // different context.
- JSFunction* object_function =
- function->context()->native_context()->object_function();
-
- // Each function prototype gets a copy of the object function map.
- // This avoid unwanted sharing of maps between prototypes of different
- // constructors.
+ // Make sure to use globals from the function's context, since the function
+ // can be from a different context.
+ Context* native_context = function->context()->native_context();
+ bool needs_constructor_property;
Map* new_map;
- ASSERT(object_function->has_initial_map());
- MaybeObject* maybe_map = object_function->initial_map()->Copy();
- if (!maybe_map->To(&new_map)) return maybe_map;
+ if (function->shared()->is_generator()) {
+ // Generator prototypes can share maps since they don't have "constructor"
+ // properties.
+ new_map = native_context->generator_object_prototype_map();
+ needs_constructor_property = false;
+ } else {
+ // Each function prototype gets a fresh map to avoid unwanted sharing of
+ // maps between prototypes of different constructors.
+ JSFunction* object_function = native_context->object_function();
+ ASSERT(object_function->has_initial_map());
+ MaybeObject* maybe_map = object_function->initial_map()->Copy();
+ if (!maybe_map->To(&new_map)) return maybe_map;
+ needs_constructor_property = true;
+ }
Object* prototype;
MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
- // When creating the prototype for the function we must set its
- // constructor to the function.
- MaybeObject* maybe_failure =
- JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
- constructor_string(), function, DONT_ENUM);
- if (maybe_failure->IsFailure()) return maybe_failure;
+ if (needs_constructor_property) {
+ MaybeObject* maybe_failure =
+ JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
+ constructor_string(), function, DONT_ENUM);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ }
return prototype;
}
@@ -4086,10 +4094,20 @@
// First create a new map with the size and number of in-object properties
// suggested by the function.
- int instance_size = fun->shared()->CalculateInstanceSize();
- int in_object_properties = fun->shared()->CalculateInObjectProperties();
+ InstanceType instance_type;
+ int instance_size;
+ int in_object_properties;
+ if (fun->shared()->is_generator()) {
+ instance_type = JS_GENERATOR_OBJECT_TYPE;
+ instance_size = JSGeneratorObject::kSize;
+ in_object_properties = 0;
+ } else {
+ instance_type = JS_OBJECT_TYPE;
+ instance_size = fun->shared()->CalculateInstanceSize();
+ in_object_properties = fun->shared()->CalculateInObjectProperties();
+ }
Map* map;
- MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
+ MaybeObject* maybe_map = AllocateMap(instance_type, instance_size);
if (!maybe_map->To(&map)) return maybe_map;
// Fetch or allocate prototype.
@@ -4111,7 +4129,8 @@
// the inline_new flag so we only change the map if we generate a
// specialized construct stub.
ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
- if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
+ if (instance_type == JS_OBJECT_TYPE &&
+ fun->shared()->CanGenerateInlineConstructor(prototype)) {
int count = fun->shared()->this_property_assignments_count();
if (count > in_object_properties) {
// Inline constructor can only handle inobject properties.
@@ -4144,7 +4163,9 @@
}
}
- fun->shared()->StartInobjectSlackTracking(map);
+ if (instance_type == JS_OBJECT_TYPE) {
+ fun->shared()->StartInobjectSlackTracking(map);
+ }
return map;
}
@@ -4327,6 +4348,22 @@
}
+MaybeObject* Heap::AllocateJSGeneratorObject(JSFunction *function) {
+ ASSERT(function->shared()->is_generator());
+ Map *map;
+ if (function->has_initial_map()) {
+ map = function->initial_map();
+ } else {
+ // Allocate the initial map if absent.
+ MaybeObject* maybe_map = AllocateInitialMap(function);
+ if (!maybe_map->To(&map)) return maybe_map;
+ function->set_initial_map(map);
+ }
+ ASSERT(map->instance_type() == JS_GENERATOR_OBJECT_TYPE);
+ return AllocateJSObjectFromMap(map);
+}
+
+
MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
// Allocate a fresh map. Modules do not have a prototype.
Map* map;
@@ -4945,7 +4982,7 @@
int len) {
// Only works for ascii.
ASSERT(vector.length() == len);
- memcpy(chars, vector.start(), len);
+ OS::MemCopy(chars, vector.start(), len);
}
static inline void WriteTwoByteData(Vector<const char> vector,
@@ -6588,11 +6625,6 @@
store_buffer()->SetUp();
- if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
-#ifdef DEBUG
- relocation_mutex_locked_ = false;
-#endif // DEBUG
-
return true;
}
@@ -6695,8 +6727,6 @@
incremental_marking()->TearDown();
isolate_->memory_allocator()->TearDown();
-
- delete relocation_mutex_;
}
@@ -7821,8 +7851,8 @@
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
#undef ADJUST_LAST_TIME_OBJECT_COUNT
- memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
- memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
+ OS::MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
+ OS::MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
ClearObjectStats();
}
diff --git a/src/heap.h b/src/heap.h
index 8992e31..7b4b70d 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -150,7 +150,6 @@
V(HeapNumber, minus_zero_value, MinusZeroValue) \
V(Map, neander_map, NeanderMap) \
V(JSObject, message_listeners, MessageListeners) \
- V(Foreign, prototype_accessors, PrototypeAccessors) \
V(UnseededNumberDictionary, code_stubs, CodeStubs) \
V(UnseededNumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(PolymorphicCodeCache, polymorphic_code_cache, PolymorphicCodeCache) \
@@ -210,9 +209,11 @@
V(index_string, "index") \
V(last_index_string, "lastIndex") \
V(object_string, "object") \
+ V(payload_string, "payload") \
V(prototype_string, "prototype") \
V(string_string, "string") \
V(String_string, "String") \
+ V(unknown_field_string, "unknownField") \
V(symbol_string, "symbol") \
V(Symbol_string, "Symbol") \
V(Date_string, "Date") \
@@ -601,6 +602,13 @@
return old_pointer_space_->allocation_limit_address();
}
+ Address* OldDataSpaceAllocationTopAddress() {
+ return old_data_space_->allocation_top_address();
+ }
+ Address* OldDataSpaceAllocationLimitAddress() {
+ return old_data_space_->allocation_limit_address();
+ }
+
// Uncommit unused semi space.
bool UncommitFromSpace() { return new_space_.UncommitFromSpace(); }
@@ -617,6 +625,9 @@
JSFunction* constructor,
Handle<Object> allocation_site_info_payload);
+ MUST_USE_RESULT MaybeObject* AllocateJSGeneratorObject(
+ JSFunction* function);
+
MUST_USE_RESULT MaybeObject* AllocateJSModule(Context* context,
ScopeInfo* scope_info);
@@ -1329,6 +1340,10 @@
inline bool InOldPointerSpace(Address address);
inline bool InOldPointerSpace(Object* object);
+ // Returns whether the object resides in old data space.
+ inline bool InOldDataSpace(Address address);
+ inline bool InOldDataSpace(Object* object);
+
// Checks whether an address/object in the heap (including auxiliary
// area and unused area).
bool Contains(Address addr);
@@ -1497,6 +1512,12 @@
MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length,
PretenureFlag pretenure);
+ // Predicate that governs global pre-tenuring decisions based on observed
+ // promotion rates of previous collections.
+ inline bool ShouldGloballyPretenure() {
+ return new_space_high_promotion_mode_active_;
+ }
+
inline intptr_t PromotedTotalSize() {
return PromotedSpaceSizeOfObjects() + PromotedExternalMemorySize();
}
@@ -1825,38 +1846,6 @@
void CheckpointObjectStats();
- // We don't use a ScopedLock here since we want to lock the heap
- // only when FLAG_parallel_recompilation is true.
- class RelocationLock {
- public:
- explicit RelocationLock(Heap* heap) : heap_(heap) {
- if (FLAG_parallel_recompilation) {
- heap_->relocation_mutex_->Lock();
-#ifdef DEBUG
- heap_->relocation_mutex_locked_ = true;
-#endif // DEBUG
- }
- }
-
- ~RelocationLock() {
- if (FLAG_parallel_recompilation) {
-#ifdef DEBUG
- heap_->relocation_mutex_locked_ = false;
-#endif // DEBUG
- heap_->relocation_mutex_->Unlock();
- }
- }
-
-#ifdef DEBUG
- static bool IsLocked(Heap* heap) {
- return heap->relocation_mutex_locked_;
- }
-#endif // DEBUG
-
- private:
- Heap* heap_;
- };
-
private:
Heap();
@@ -2326,11 +2315,6 @@
MemoryChunk* chunks_queued_for_free_;
- Mutex* relocation_mutex_;
-#ifdef DEBUG
- bool relocation_mutex_locked_;
-#endif // DEBUG;
-
friend class Factory;
friend class GCTracer;
friend class DisallowAllocationFailure;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index edbffc2..60a6912 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -685,7 +685,7 @@
HValue* operand = OperandAt(i);
if (operand == NULL) continue;
HUseListNode* first = operand->use_list_;
- if (first != NULL && first->value() == this && first->index() == i) {
+ if (first != NULL && first->value()->CheckFlag(kIsDead)) {
operand->use_list_ = first->tail();
}
}
@@ -806,6 +806,9 @@
PrintRangeTo(stream);
PrintChangesTo(stream);
PrintTypeTo(stream);
+ if (CheckFlag(HValue::kHasNoObservableSideEffects)) {
+ stream->Add(" [noOSE]");
+ }
}
@@ -1581,10 +1584,10 @@
// for which the map is known.
if (HasNoUses() && dominator->IsStoreNamedField()) {
HStoreNamedField* store = HStoreNamedField::cast(dominator);
- Handle<Map> map = store->transition();
- if (map.is_null() || store->object() != value()) return;
+ UniqueValueId map_unique_id = store->transition_unique_id();
+ if (!map_unique_id.IsInitialized() || store->object() != value()) return;
for (int i = 0; i < map_set()->length(); i++) {
- if (map.is_identical_to(map_set()->at(i))) {
+ if (map_unique_id == map_unique_ids_.at(i)) {
DeleteAndReplaceWith(NULL);
return;
}
@@ -1980,20 +1983,25 @@
}
-void HSimulate::MergeInto(HSimulate* other) {
- for (int i = 0; i < values_.length(); ++i) {
- HValue* value = values_[i];
- if (HasAssignedIndexAt(i)) {
- other->AddAssignedValue(GetAssignedIndexAt(i), value);
- } else {
- if (other->pop_count_ > 0) {
- other->pop_count_--;
+void HSimulate::MergeWith(ZoneList<HSimulate*>* list) {
+ while (!list->is_empty()) {
+ HSimulate* from = list->RemoveLast();
+ ZoneList<HValue*>* from_values = &from->values_;
+ for (int i = 0; i < from_values->length(); ++i) {
+ if (from->HasAssignedIndexAt(i)) {
+ AddAssignedValue(from->GetAssignedIndexAt(i),
+ from_values->at(i));
} else {
- other->AddPushedValue(value);
+ if (pop_count_ > 0) {
+ pop_count_--;
+ } else {
+ AddPushedValue(from_values->at(i));
+ }
}
}
+ pop_count_ += from->pop_count_;
+ from->DeleteAndReplaceWith(NULL);
}
- other->pop_count_ += pop_count();
}
@@ -2039,6 +2047,7 @@
HConstant::HConstant(Handle<Object> handle, Representation r)
: handle_(handle),
+ unique_id_(),
has_int32_value_(false),
has_double_value_(false),
is_internalized_string_(false),
@@ -2067,11 +2076,13 @@
HConstant::HConstant(Handle<Object> handle,
+ UniqueValueId unique_id,
Representation r,
HType type,
bool is_internalize_string,
bool boolean_value)
: handle_(handle),
+ unique_id_(unique_id),
has_int32_value_(false),
has_double_value_(false),
is_internalized_string_(is_internalize_string),
@@ -2087,7 +2098,9 @@
HConstant::HConstant(int32_t integer_value,
Representation r,
Handle<Object> optional_handle)
- : has_int32_value_(true),
+ : handle_(optional_handle),
+ unique_id_(),
+ has_int32_value_(true),
has_double_value_(true),
is_internalized_string_(false),
boolean_value_(integer_value != 0),
@@ -2100,7 +2113,9 @@
HConstant::HConstant(double double_value,
Representation r,
Handle<Object> optional_handle)
- : has_int32_value_(IsInteger32(double_value)),
+ : handle_(optional_handle),
+ unique_id_(),
+ has_int32_value_(IsInteger32(double_value)),
has_double_value_(true),
is_internalized_string_(false),
boolean_value_(double_value != 0 && !isnan(double_value)),
@@ -2125,8 +2140,12 @@
if (has_int32_value_) return new(zone) HConstant(int32_value_, r, handle_);
if (has_double_value_) return new(zone) HConstant(double_value_, r, handle_);
ASSERT(!handle_.is_null());
- return new(zone) HConstant(
- handle_, r, type_from_value_, is_internalized_string_, boolean_value_);
+ return new(zone) HConstant(handle_,
+ unique_id_,
+ r,
+ type_from_value_,
+ is_internalized_string_,
+ boolean_value_);
}
@@ -2451,6 +2470,8 @@
Zone* zone)
: types_(Min(types->length(), kMaxLoadPolymorphism), zone),
name_(name),
+ types_unique_ids_(0, zone),
+ name_unique_id_(),
need_generic_(false) {
SetOperandAt(0, context);
SetOperandAt(1, object);
@@ -2517,15 +2538,39 @@
}
-bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
- HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
- if (types_.length() != other->types()->length()) return false;
- if (!name_.is_identical_to(other->name())) return false;
- if (need_generic_ != other->need_generic_) return false;
+void HCheckMaps::FinalizeUniqueValueId() {
+ if (!map_unique_ids_.is_empty()) return;
+ Zone* zone = block()->zone();
+ map_unique_ids_.Initialize(map_set_.length(), zone);
+ for (int i = 0; i < map_set_.length(); i++) {
+ map_unique_ids_.Add(UniqueValueId(map_set_.at(i)), zone);
+ }
+}
+
+
+void HLoadNamedFieldPolymorphic::FinalizeUniqueValueId() {
+ if (!types_unique_ids_.is_empty()) return;
+ Zone* zone = block()->zone();
+ types_unique_ids_.Initialize(types_.length(), zone);
for (int i = 0; i < types_.length(); i++) {
+ types_unique_ids_.Add(UniqueValueId(types_.at(i)), zone);
+ }
+ name_unique_id_ = UniqueValueId(name_);
+}
+
+
+bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
+ ASSERT_EQ(types_.length(), types_unique_ids_.length());
+ HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
+ if (name_unique_id_ != other->name_unique_id_) return false;
+ if (types_unique_ids_.length() != other->types_unique_ids_.length()) {
+ return false;
+ }
+ if (need_generic_ != other->need_generic_) return false;
+ for (int i = 0; i < types_unique_ids_.length(); i++) {
bool found = false;
- for (int j = 0; j < types_.length(); j++) {
- if (types_.at(j).is_identical_to(other->types()->at(i))) {
+ for (int j = 0; j < types_unique_ids_.length(); j++) {
+ if (types_unique_ids_.at(j) == other->types_unique_ids_.at(i)) {
found = true;
break;
}
@@ -2916,12 +2961,6 @@
}
-HType HFastLiteral::CalculateInferredType() {
- // TODO(mstarzinger): Be smarter, could also be JSArray here.
- return HType::JSObject();
-}
-
-
HType HArrayLiteral::CalculateInferredType() {
return HType::JSArray();
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index ad03687..6853dfe 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -111,7 +111,6 @@
V(DummyUse) \
V(ElementsKind) \
V(EnterInlined) \
- V(FastLiteral) \
V(FixedArrayBaseLength) \
V(ForceRepresentation) \
V(FunctionLiteral) \
@@ -235,14 +234,6 @@
virtual Opcode opcode() const { return HValue::k##type; }
-#ifdef DEBUG
-#define ASSERT_ALLOCATION_DISABLED \
- ASSERT(isolate()->optimizing_compiler_thread()->IsOptimizerThread() || \
- !isolate()->heap()->IsAllocationAllowed())
-#else
-#define ASSERT_ALLOCATION_DISABLED do {} while (0)
-#endif
-
class Range: public ZoneObject {
public:
Range()
@@ -365,6 +356,48 @@
};
+class UniqueValueId {
+ public:
+ UniqueValueId() : raw_address_(NULL) { }
+
+ explicit UniqueValueId(Object* object) {
+ raw_address_ = reinterpret_cast<Address>(object);
+ ASSERT(IsInitialized());
+ }
+
+ explicit UniqueValueId(Handle<Object> handle) {
+ static const Address kEmptyHandleSentinel = reinterpret_cast<Address>(1);
+ if (handle.is_null()) {
+ raw_address_ = kEmptyHandleSentinel;
+ } else {
+ raw_address_ = reinterpret_cast<Address>(*handle);
+ ASSERT_NE(kEmptyHandleSentinel, raw_address_);
+ }
+ ASSERT(IsInitialized());
+ }
+
+ bool IsInitialized() const { return raw_address_ != NULL; }
+
+ bool operator==(const UniqueValueId& other) const {
+ ASSERT(IsInitialized() && other.IsInitialized());
+ return raw_address_ == other.raw_address_;
+ }
+
+ bool operator!=(const UniqueValueId& other) const {
+ ASSERT(IsInitialized() && other.IsInitialized());
+ return raw_address_ != other.raw_address_;
+ }
+
+ intptr_t Hashcode() const {
+ ASSERT(IsInitialized());
+ return reinterpret_cast<intptr_t>(raw_address_);
+ }
+
+ private:
+ Address raw_address_;
+};
+
+
class HType {
public:
HType() : type_(kUninitialized) { }
@@ -829,6 +862,7 @@
// This flag is set to true after the SetupInformativeDefinitions() pass
// has processed this instruction.
kIDefsProcessingDone,
+ kHasNoObservableSideEffects,
kLastFlag = kIDefsProcessingDone
};
@@ -1006,7 +1040,8 @@
return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
}
bool HasObservableSideEffects() const {
- return gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
+ return !CheckFlag(kHasNoObservableSideEffects) &&
+ gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
}
GVNFlagSet DependsOnFlags() const {
@@ -1056,6 +1091,9 @@
bool Equals(HValue* other);
virtual intptr_t Hashcode();
+ // Compute unique ids upfront that is safe wrt GC and parallel recompilation.
+ virtual void FinalizeUniqueValueId() { }
+
// Printing support.
virtual void PrintTo(StringStream* stream) = 0;
void PrintNameTo(StringStream* stream);
@@ -1830,7 +1868,7 @@
return Representation::None();
}
- void MergeInto(HSimulate* other);
+ void MergeWith(ZoneList<HSimulate*>* list);
bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
DECLARE_CONCRETE_INSTRUCTION(Simulate)
@@ -2642,7 +2680,8 @@
class HCheckMaps: public HTemplateInstruction<2> {
public:
HCheckMaps(HValue* value, Handle<Map> map, Zone* zone,
- HValue* typecheck = NULL) {
+ HValue* typecheck = NULL)
+ : map_unique_ids_(0, zone) {
SetOperandAt(0, value);
// If callers don't depend on a typecheck, they can pass in NULL. In that
// case we use a copy of the |value| argument as a dummy value.
@@ -2654,7 +2693,8 @@
SetGVNFlag(kDependsOnElementsKind);
map_set()->Add(map, zone);
}
- HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) {
+ HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone)
+ : map_unique_ids_(0, zone) {
SetOperandAt(0, value);
SetOperandAt(1, value);
set_representation(Representation::Tagged());
@@ -2701,28 +2741,36 @@
HValue* value() { return OperandAt(0); }
SmallMapList* map_set() { return &map_set_; }
+ virtual void FinalizeUniqueValueId();
+
DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
protected:
virtual bool DataEquals(HValue* other) {
+ ASSERT_EQ(map_set_.length(), map_unique_ids_.length());
HCheckMaps* b = HCheckMaps::cast(other);
// Relies on the fact that map_set has been sorted before.
- if (map_set()->length() != b->map_set()->length()) return false;
- for (int i = 0; i < map_set()->length(); i++) {
- if (!map_set()->at(i).is_identical_to(b->map_set()->at(i))) return false;
+ if (map_unique_ids_.length() != b->map_unique_ids_.length()) {
+ return false;
+ }
+ for (int i = 0; i < map_unique_ids_.length(); i++) {
+ if (map_unique_ids_.at(i) != b->map_unique_ids_.at(i)) {
+ return false;
+ }
}
return true;
}
private:
SmallMapList map_set_;
+ ZoneList<UniqueValueId> map_unique_ids_;
};
class HCheckFunction: public HUnaryOperation {
public:
HCheckFunction(HValue* value, Handle<JSFunction> function)
- : HUnaryOperation(value), target_(function) {
+ : HUnaryOperation(value), target_(function), target_unique_id_() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function);
@@ -2738,6 +2786,10 @@
virtual void Verify();
#endif
+ virtual void FinalizeUniqueValueId() {
+ target_unique_id_ = UniqueValueId(target_);
+ }
+
Handle<JSFunction> target() const { return target_; }
bool target_in_new_space() const { return target_in_new_space_; }
@@ -2746,11 +2798,12 @@
protected:
virtual bool DataEquals(HValue* other) {
HCheckFunction* b = HCheckFunction::cast(other);
- return target_.is_identical_to(b->target());
+ return target_unique_id_ == b->target_unique_id_;
}
private:
Handle<JSFunction> target_;
+ UniqueValueId target_unique_id_;
bool target_in_new_space_;
};
@@ -2855,7 +2908,11 @@
public:
HCheckPrototypeMaps(Handle<JSObject> prototype,
Handle<JSObject> holder,
- Zone* zone) : prototypes_(2, zone), maps_(2, zone) {
+ Zone* zone)
+ : prototypes_(2, zone),
+ maps_(2, zone),
+ first_prototype_unique_id_(),
+ last_prototype_unique_id_() {
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
// Keep a list of all objects on the prototype chain up to the holder
@@ -2881,18 +2938,13 @@
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
- ASSERT_ALLOCATION_DISABLED;
- // Dereferencing to use the object's raw address for hashing is safe.
- HandleDereferenceGuard allow_handle_deref(isolate(),
- HandleDereferenceGuard::ALLOW);
- SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
- !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
- intptr_t hash = 0;
- for (int i = 0; i < prototypes_.length(); i++) {
- hash = 17 * hash + reinterpret_cast<intptr_t>(*prototypes_[i]);
- hash = 17 * hash + reinterpret_cast<intptr_t>(*maps_[i]);
- }
- return hash;
+ return first_prototype_unique_id_.Hashcode() * 17 +
+ last_prototype_unique_id_.Hashcode();
+ }
+
+ virtual void FinalizeUniqueValueId() {
+ first_prototype_unique_id_ = UniqueValueId(prototypes_.first());
+ last_prototype_unique_id_ = UniqueValueId(prototypes_.last());
}
bool CanOmitPrototypeChecks() {
@@ -2905,22 +2957,15 @@
protected:
virtual bool DataEquals(HValue* other) {
HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
-#ifdef DEBUG
- if (prototypes_.length() != b->prototypes()->length()) return false;
- for (int i = 0; i < prototypes_.length(); i++) {
- if (!prototypes_[i].is_identical_to(b->prototypes()->at(i))) return false;
- if (!maps_[i].is_identical_to(b->maps()->at(i))) return false;
- }
- return true;
-#else
- return prototypes_.first().is_identical_to(b->prototypes()->first()) &&
- prototypes_.last().is_identical_to(b->prototypes()->last());
-#endif // DEBUG
+ return first_prototype_unique_id_ == b->first_prototype_unique_id_ &&
+ last_prototype_unique_id_ == b->last_prototype_unique_id_;
}
private:
ZoneList<Handle<JSObject> > prototypes_;
ZoneList<Handle<Map> > maps_;
+ UniqueValueId first_prototype_unique_id_;
+ UniqueValueId last_prototype_unique_id_;
};
@@ -3175,6 +3220,7 @@
Representation r,
Handle<Object> optional_handle = Handle<Object>::null());
HConstant(Handle<Object> handle,
+ UniqueValueId unique_id,
Representation r,
HType type,
bool is_internalized_string,
@@ -3188,35 +3234,36 @@
return handle_;
}
- bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); }
+ bool IsSpecialDouble() const {
+ return has_double_value_ &&
+ (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
+ FixedDoubleArray::is_the_hole_nan(double_value_) ||
+ isnan(double_value_));
+ }
bool ImmortalImmovable() const {
if (has_int32_value_) {
return false;
}
if (has_double_value_) {
- if (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
- isnan(double_value_)) {
+ if (IsSpecialDouble()) {
return true;
}
return false;
}
ASSERT(!handle_.is_null());
+ HandleDereferenceGuard allow_dereference_for_immovable_check(
+ isolate(), HandleDereferenceGuard::ALLOW);
Heap* heap = isolate()->heap();
- // We should have handled minus_zero_value and nan_value in the
- // has_double_value_ clause above.
- // Dereferencing is safe to compare against immovable singletons.
- HandleDereferenceGuard allow_handle_deref(isolate(),
- HandleDereferenceGuard::ALLOW);
- ASSERT(*handle_ != heap->minus_zero_value());
- ASSERT(*handle_ != heap->nan_value());
- return *handle_ == heap->undefined_value() ||
- *handle_ == heap->null_value() ||
- *handle_ == heap->true_value() ||
- *handle_ == heap->false_value() ||
- *handle_ == heap->the_hole_value() ||
- *handle_ == heap->empty_string();
+ ASSERT(unique_id_ != UniqueValueId(heap->minus_zero_value()));
+ ASSERT(unique_id_ != UniqueValueId(heap->nan_value()));
+ return unique_id_ == UniqueValueId(heap->undefined_value()) ||
+ unique_id_ == UniqueValueId(heap->null_value()) ||
+ unique_id_ == UniqueValueId(heap->true_value()) ||
+ unique_id_ == UniqueValueId(heap->false_value()) ||
+ unique_id_ == UniqueValueId(heap->the_hole_value()) ||
+ unique_id_ == UniqueValueId(heap->empty_string());
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -3227,7 +3274,9 @@
return has_int32_value_;
}
- virtual bool EmitAtUses() { return !representation().IsDouble(); }
+ virtual bool EmitAtUses() {
+ return !representation().IsDouble() || IsSpecialDouble();
+ }
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() { return handle()->IsSmi(); }
@@ -3246,6 +3295,16 @@
ASSERT(HasDoubleValue());
return double_value_;
}
+ bool IsTheHole() const {
+ if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
+ return true;
+ }
+ Heap* heap = isolate()->heap();
+ if (!handle_.is_null() && *handle_ == heap->the_hole_value()) {
+ return true;
+ }
+ return false;
+ }
bool HasNumberValue() const { return has_double_value_; }
int32_t NumberValueAsInteger32() const {
ASSERT(HasNumberValue());
@@ -3274,24 +3333,21 @@
}
virtual intptr_t Hashcode() {
- ASSERT_ALLOCATION_DISABLED;
- intptr_t hash;
-
if (has_int32_value_) {
- hash = static_cast<intptr_t>(int32_value_);
+ return static_cast<intptr_t>(int32_value_);
} else if (has_double_value_) {
- hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_));
+ return static_cast<intptr_t>(BitCast<int64_t>(double_value_));
} else {
ASSERT(!handle_.is_null());
- // Dereferencing to use the object's raw address for hashing is safe.
- HandleDereferenceGuard allow_handle_deref(isolate(),
- HandleDereferenceGuard::ALLOW);
- SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
- !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
- hash = reinterpret_cast<intptr_t>(*handle_);
+ return unique_id_.Hashcode();
}
+ }
- return hash;
+ virtual void FinalizeUniqueValueId() {
+ if (!has_double_value_) {
+ ASSERT(!handle_.is_null());
+ unique_id_ = UniqueValueId(handle_);
+ }
}
#ifdef DEBUG
@@ -3315,7 +3371,7 @@
} else {
ASSERT(!handle_.is_null());
return !other_constant->handle_.is_null() &&
- handle_.is_identical_to(other_constant->handle_);
+ unique_id_ == other_constant->unique_id_;
}
}
@@ -3329,6 +3385,7 @@
// constant is non-numeric, handle_ always points to a valid
// constant HeapObject.
Handle<Object> handle_;
+ UniqueValueId unique_id_;
// We store the HConstant in the most specific form safely possible.
// The two flags, has_int32_value_ and has_double_value_ tell us if
@@ -4740,7 +4797,7 @@
class HLoadGlobalCell: public HTemplateInstruction<0> {
public:
HLoadGlobalCell(Handle<JSGlobalPropertyCell> cell, PropertyDetails details)
- : cell_(cell), details_(details) {
+ : cell_(cell), details_(details), unique_id_() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnGlobalVars);
@@ -4752,13 +4809,11 @@
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
- ASSERT_ALLOCATION_DISABLED;
- // Dereferencing to use the object's raw address for hashing is safe.
- HandleDereferenceGuard allow_handle_deref(isolate(),
- HandleDereferenceGuard::ALLOW);
- SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
- !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
- return reinterpret_cast<intptr_t>(*cell_);
+ return unique_id_.Hashcode();
+ }
+
+ virtual void FinalizeUniqueValueId() {
+ unique_id_ = UniqueValueId(cell_);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -4770,7 +4825,7 @@
protected:
virtual bool DataEquals(HValue* other) {
HLoadGlobalCell* b = HLoadGlobalCell::cast(other);
- return cell_.is_identical_to(b->cell());
+ return unique_id_ == b->unique_id_;
}
private:
@@ -4778,6 +4833,7 @@
Handle<JSGlobalPropertyCell> cell_;
PropertyDetails details_;
+ UniqueValueId unique_id_;
};
@@ -4860,7 +4916,6 @@
HAllocate(HValue* context, HValue* size, HType type, Flags flags)
: type_(type),
flags_(flags) {
- ASSERT((flags & CAN_ALLOCATE_IN_OLD_DATA_SPACE) == 0); // unimplemented
SetOperandAt(0, context);
SetOperandAt(1, size);
set_representation(Representation::Tagged());
@@ -4955,7 +5010,6 @@
new_space_dominator);
}
if (object != new_space_dominator) return true;
- if (object->IsFastLiteral()) return false;
if (object->IsAllocateObject()) return false;
if (object->IsAllocate()) {
return !HAllocate::cast(object)->GuaranteedInNewSpace();
@@ -5238,12 +5292,16 @@
static const int kMaxLoadPolymorphism = 4;
+ virtual void FinalizeUniqueValueId();
+
protected:
virtual bool DataEquals(HValue* value);
private:
SmallMapList types_;
Handle<String> name_;
+ ZoneList<UniqueValueId> types_unique_ids_;
+ UniqueValueId name_unique_id_;
bool need_generic_;
};
@@ -5507,6 +5565,7 @@
: name_(name),
is_in_object_(in_object),
offset_(offset),
+ transition_unique_id_(),
new_space_dominator_(NULL) {
SetOperandAt(0, obj);
SetOperandAt(1, val);
@@ -5537,6 +5596,7 @@
bool is_in_object() const { return is_in_object_; }
int offset() const { return offset_; }
Handle<Map> transition() const { return transition_; }
+ UniqueValueId transition_unique_id() const { return transition_unique_id_; }
void set_transition(Handle<Map> map) { transition_ = map; }
HValue* new_space_dominator() const { return new_space_dominator_; }
@@ -5549,11 +5609,16 @@
return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
}
+ virtual void FinalizeUniqueValueId() {
+ transition_unique_id_ = UniqueValueId(transition_);
+ }
+
private:
Handle<String> name_;
bool is_in_object_;
int offset_;
Handle<Map> transition_;
+ UniqueValueId transition_unique_id_;
HValue* new_space_dominator_;
};
@@ -5677,6 +5742,10 @@
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
+ bool IsConstantHoleStore() {
+ return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
+ }
+
virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
new_space_dominator_ = dominator;
@@ -5750,6 +5819,8 @@
Handle<Map> transitioned_map)
: original_map_(original_map),
transitioned_map_(transitioned_map),
+ original_map_unique_id_(),
+ transitioned_map_unique_id_(),
from_kind_(original_map->elements_kind()),
to_kind_(transitioned_map->elements_kind()) {
SetOperandAt(0, object);
@@ -5780,18 +5851,25 @@
virtual void PrintDataTo(StringStream* stream);
+ virtual void FinalizeUniqueValueId() {
+ original_map_unique_id_ = UniqueValueId(original_map_);
+ transitioned_map_unique_id_ = UniqueValueId(transitioned_map_);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
protected:
virtual bool DataEquals(HValue* other) {
HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
- return original_map_.is_identical_to(instr->original_map()) &&
- transitioned_map_.is_identical_to(instr->transitioned_map());
+ return original_map_unique_id_ == instr->original_map_unique_id_ &&
+ transitioned_map_unique_id_ == instr->transitioned_map_unique_id_;
}
private:
Handle<Map> original_map_;
Handle<Map> transitioned_map_;
+ UniqueValueId original_map_unique_id_;
+ UniqueValueId transitioned_map_unique_id_;
ElementsKind from_kind_;
ElementsKind to_kind_;
};
@@ -5966,45 +6044,6 @@
};
-class HFastLiteral: public HMaterializedLiteral<1> {
- public:
- HFastLiteral(HValue* context,
- Handle<JSObject> boilerplate,
- int total_size,
- int literal_index,
- int depth,
- AllocationSiteMode mode)
- : HMaterializedLiteral<1>(literal_index, depth, mode),
- boilerplate_(boilerplate),
- total_size_(total_size) {
- SetOperandAt(0, context);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
-
- // Maximum depth and total number of elements and properties for literal
- // graphs to be considered for fast deep-copying.
- static const int kMaxLiteralDepth = 3;
- static const int kMaxLiteralProperties = 8;
-
- HValue* context() { return OperandAt(0); }
- Handle<JSObject> boilerplate() const { return boilerplate_; }
- int total_size() const { return total_size_; }
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
- virtual Handle<Map> GetMonomorphicJSObjectMap() {
- return Handle<Map>(boilerplate()->map());
- }
- virtual HType CalculateInferredType();
-
- DECLARE_CONCRETE_INSTRUCTION(FastLiteral)
-
- private:
- Handle<JSObject> boilerplate_;
- int total_size_;
-};
-
-
class HArrayLiteral: public HMaterializedLiteral<1> {
public:
HArrayLiteral(HValue* context,
@@ -6192,7 +6231,7 @@
// This instruction is not marked as having side effects, but
// changes the map of the input operand. Use it only when creating
// object literals.
- ASSERT(value->IsObjectLiteral() || value->IsFastLiteral());
+ ASSERT(value->IsObjectLiteral());
set_representation(Representation::Tagged());
}
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index abff7b7..127d7a9 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -517,7 +517,6 @@
void HGraph::Verify(bool do_full_verify) const {
// Allow dereferencing for debug mode verification.
- Heap::RelocationLock(isolate()->heap());
HandleDereferenceGuard allow_handle_deref(isolate(),
HandleDereferenceGuard::ALLOW);
for (int i = 0; i < blocks_.length(); i++) {
@@ -619,6 +618,7 @@
if (!constant_##name##_.is_set()) { \
HConstant* constant = new(zone()) HConstant( \
isolate()->factory()->name##_value(), \
+ UniqueValueId(isolate()->heap()->name##_value()), \
Representation::Tagged(), \
htype, \
false, \
@@ -880,6 +880,7 @@
HPhase phase("H_Block building", isolate());
set_current_block(graph()->entry_block());
if (!BuildGraph()) return NULL;
+ graph()->FinalizeUniqueValueIds();
return graph_;
}
@@ -887,6 +888,9 @@
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
ASSERT(current_block() != NULL);
current_block()->AddInstruction(instr);
+ if (no_side_effects_scope_count_ > 0) {
+ instr->SetFlag(HValue::kHasNoObservableSideEffects);
+ }
return instr;
}
@@ -894,6 +898,7 @@
void HGraphBuilder::AddSimulate(BailoutId id,
RemovableSimulate removable) {
ASSERT(current_block() != NULL);
+ ASSERT(no_side_effects_scope_count_ == 0);
current_block()->AddSimulate(id, removable);
environment()->set_previous_ast_id(id);
}
@@ -1041,7 +1046,6 @@
HValue* length,
HValue* key,
bool is_js_array) {
- BailoutId ast_id = environment()->previous_ast_id();
Zone* zone = this->zone();
IfBuilder length_checker(this);
@@ -1074,7 +1078,6 @@
HAdd::New(zone, context, length, graph_->GetConstant1()));
new_length->ChangeRepresentation(Representation::Integer32());
new_length->ClearFlag(HValue::kCanOverflow);
- AddSimulate(ast_id, REMOVABLE_SIMULATE);
Factory* factory = isolate()->factory();
HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
@@ -1083,7 +1086,6 @@
new_length, true,
JSArray::kLengthOffset));
length_store->SetGVNFlag(kChangesArrayLengths);
- AddSimulate(ast_id, REMOVABLE_SIMULATE);
}
length_checker.BeginElse();
@@ -1210,6 +1212,8 @@
}
if (IsGrowStoreMode(store_mode)) {
+ NoObservableSideEffectsScope no_effects(this);
+
elements = BuildCheckForCapacityGrow(object, elements, elements_kind,
length, key, is_js_array);
checked_key = key;
@@ -1219,6 +1223,8 @@
if (is_store && (fast_elements || fast_smi_only_elements)) {
if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
+ NoObservableSideEffectsScope no_effects(this);
+
elements = BuildCopyElementsOnWrite(object, elements, elements_kind,
length);
} else {
@@ -1238,7 +1244,6 @@
HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
ElementsKind kind,
HValue* capacity) {
- BailoutId ast_id = current_block()->last_environment()->previous_ast_id();
Zone* zone = this->zone();
int elements_size = IsFastDoubleElementsKind(kind)
@@ -1260,10 +1265,14 @@
total_size->ClearFlag(HValue::kCanOverflow);
HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
- // TODO(hpayer): add support for old data space
- if (FLAG_pretenure_literals && !IsFastDoubleElementsKind(kind)) {
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
+ if (FLAG_pretenure_literals) {
+ if (IsFastDoubleElementsKind(kind)) {
+ flags = static_cast<HAllocate::Flags>(
+ flags | HAllocate::CAN_ALLOCATE_IN_OLD_DATA_SPACE);
+ } else {
+ flags = static_cast<HAllocate::Flags>(
+ flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
+ }
}
if (IsFastDoubleElementsKind(kind)) {
flags = static_cast<HAllocate::Flags>(
@@ -1273,27 +1282,40 @@
HValue* elements =
AddInstruction(new(zone) HAllocate(context, total_size,
HType::JSArray(), flags));
+ return elements;
+}
+
+void HGraphBuilder::BuildInitializeElements(HValue* elements,
+ ElementsKind kind,
+ HValue* capacity) {
+ Zone* zone = this->zone();
Factory* factory = isolate()->factory();
Handle<Map> map = IsFastDoubleElementsKind(kind)
? factory->fixed_double_array_map()
: factory->fixed_array_map();
- BuildStoreMap(elements, map, ast_id);
+ BuildStoreMap(elements, map);
Handle<String> fixed_array_length_field_name = factory->length_field_string();
HInstruction* store_length =
new(zone) HStoreNamedField(elements, fixed_array_length_field_name,
capacity, true, FixedArray::kLengthOffset);
AddInstruction(store_length);
- AddSimulate(ast_id, REMOVABLE_SIMULATE);
+}
- return elements;
+
+HValue* HGraphBuilder::BuildAllocateAndInitializeElements(HValue* context,
+ ElementsKind kind,
+ HValue* capacity) {
+ HValue* new_elements =
+ BuildAllocateElements(context, kind, capacity);
+ BuildInitializeElements(new_elements, kind, capacity);
+ return new_elements;
}
HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
- HValue* map,
- BailoutId id) {
+ HValue* map) {
Zone* zone = this->zone();
Factory* factory = isolate()->factory();
Handle<String> map_field_name = factory->map_field_string();
@@ -1302,18 +1324,16 @@
true, JSObject::kMapOffset);
store_map->SetGVNFlag(kChangesMaps);
AddInstruction(store_map);
- AddSimulate(id, REMOVABLE_SIMULATE);
return store_map;
}
HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
- Handle<Map> map,
- BailoutId id) {
+ Handle<Map> map) {
Zone* zone = this->zone();
HValue* map_constant =
AddInstruction(new(zone) HConstant(map, Representation::Tagged()));
- return BuildStoreMap(object, map_constant, id);
+ return BuildStoreMap(object, map_constant);
}
@@ -1372,7 +1392,7 @@
BuildNewSpaceArrayCheck(new_capacity, kind);
HValue* new_elements =
- BuildAllocateElements(context, kind, new_capacity);
+ BuildAllocateAndInitializeElements(context, kind, new_capacity);
BuildCopyElements(context, elements, kind,
new_elements, kind,
@@ -1395,7 +1415,6 @@
ElementsKind elements_kind,
HValue* from,
HValue* to) {
- BailoutId ast_id = current_block()->last_environment()->previous_ast_id();
// Fast elements kinds need to be initialized in case statements below cause
// a garbage collection.
Factory* factory = isolate()->factory();
@@ -1413,7 +1432,6 @@
HValue* key = builder.BeginBody(from, to, Token::LT);
AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind));
- AddSimulate(ast_id, REMOVABLE_SIMULATE);
builder.EndBody();
}
@@ -1426,7 +1444,6 @@
ElementsKind to_elements_kind,
HValue* length,
HValue* capacity) {
- BailoutId ast_id = environment()->previous_ast_id();
bool pre_fill_with_holes =
IsFastDoubleElementsKind(from_elements_kind) &&
IsFastObjectElementsKind(to_elements_kind);
@@ -1450,7 +1467,6 @@
AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element,
to_elements_kind));
- AddSimulate(ast_id, REMOVABLE_SIMULATE);
builder.EndBody();
@@ -1462,6 +1478,119 @@
}
+HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
+ HValue* boilerplate,
+ AllocationSiteMode mode,
+ ElementsKind kind,
+ int length) {
+ Zone* zone = this->zone();
+ Factory* factory = isolate()->factory();
+
+ NoObservableSideEffectsScope no_effects(this);
+
+ // All sizes here are multiples of kPointerSize.
+ int size = JSArray::kSize;
+ if (mode == TRACK_ALLOCATION_SITE) {
+ size += AllocationSiteInfo::kSize;
+ }
+ int elems_offset = size;
+ if (length > 0) {
+ size += IsFastDoubleElementsKind(kind)
+ ? FixedDoubleArray::SizeFor(length)
+ : FixedArray::SizeFor(length);
+ }
+
+ HAllocate::Flags allocate_flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
+ if (IsFastDoubleElementsKind(kind)) {
+ allocate_flags = static_cast<HAllocate::Flags>(
+ allocate_flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED);
+ }
+
+ // Allocate both the JS array and the elements array in one big
+ // allocation. This avoids multiple limit checks.
+ HValue* size_in_bytes =
+ AddInstruction(new(zone) HConstant(size, Representation::Integer32()));
+ HInstruction* object =
+ AddInstruction(new(zone) HAllocate(context,
+ size_in_bytes,
+ HType::JSObject(),
+ allocate_flags));
+
+ // Copy the JS array part.
+ for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
+ if ((i != JSArray::kElementsOffset) || (length == 0)) {
+ HInstruction* value =
+ AddInstruction(new(zone) HLoadNamedField(boilerplate, true, i));
+ if (i != JSArray::kMapOffset) {
+ AddInstruction(new(zone) HStoreNamedField(object,
+ factory->empty_string(),
+ value,
+ true, i));
+ } else {
+ BuildStoreMap(object, value);
+ }
+ }
+ }
+
+ // Create an allocation site info if requested.
+ if (mode == TRACK_ALLOCATION_SITE) {
+ HValue* alloc_site =
+ AddInstruction(new(zone) HInnerAllocatedObject(object, JSArray::kSize));
+ Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
+ BuildStoreMap(alloc_site, alloc_site_map);
+ int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset;
+ AddInstruction(new(zone) HStoreNamedField(alloc_site,
+ factory->empty_string(),
+ boilerplate,
+ true, alloc_payload_offset));
+ }
+
+ if (length > 0) {
+ // Get hold of the elements array of the boilerplate and setup the
+ // elements pointer in the resulting object.
+ HValue* boilerplate_elements =
+ AddInstruction(new(zone) HLoadElements(boilerplate, NULL));
+ HValue* object_elements =
+ AddInstruction(new(zone) HInnerAllocatedObject(object, elems_offset));
+ AddInstruction(new(zone) HStoreNamedField(object,
+ factory->elements_field_string(),
+ object_elements,
+ true, JSObject::kElementsOffset));
+
+ // Copy the elements array header.
+ for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
+ HInstruction* value =
+ AddInstruction(new(zone) HLoadNamedField(boilerplate_elements,
+ true, i));
+ AddInstruction(new(zone) HStoreNamedField(object_elements,
+ factory->empty_string(),
+ value,
+ true, i));
+ }
+
+ // Copy the elements array contents.
+ // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold
+ // copying loops with constant length up to a given boundary and use this
+ // helper here instead.
+ for (int i = 0; i < length; i++) {
+ HValue* key_constant =
+ AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+ HInstruction* value =
+ AddInstruction(new(zone) HLoadKeyed(boilerplate_elements,
+ key_constant,
+ NULL,
+ kind));
+ AddInstruction(new(zone) HStoreKeyed(object_elements,
+ key_constant,
+ value,
+ kind));
+ }
+ }
+
+ return object;
+}
+
+
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
TypeFeedbackOracle* oracle)
: HGraphBuilder(info),
@@ -1568,6 +1697,19 @@
}
+void HGraph::FinalizeUniqueValueIds() {
+ AssertNoAllocation no_gc;
+ ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+ for (int i = 0; i < blocks()->length(); ++i) {
+ for (HInstruction* instr = blocks()->at(i)->first();
+ instr != NULL;
+ instr = instr->next()) {
+ instr->FinalizeUniqueValueId();
+ }
+ }
+}
+
+
void HGraph::Canonicalize() {
if (!FLAG_use_canonicalizing) return;
HPhase phase("H_Canonicalize", this);
@@ -2358,8 +2500,10 @@
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));
+ OS::MemCopy(
+ array_, other->array_, array_size_ * sizeof(HValueMapListElement));
+ OS::MemCopy(
+ lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
}
@@ -2485,7 +2629,7 @@
lists_ = new_lists;
if (old_lists != NULL) {
- memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
+ OS::MemCopy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
}
for (int i = old_size; i < lists_size_; ++i) {
lists_[i].next = free_list_head_;
@@ -2531,7 +2675,7 @@
HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) {
if (this != &other) {
- memcpy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize);
+ OS::MemCopy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize);
}
return *this;
}
@@ -2829,7 +2973,7 @@
size_t string_len = strlen(underlying_buffer) + 1;
ASSERT(string_len <= sizeof(underlying_buffer));
char* result = new char[strlen(underlying_buffer) + 1];
- memcpy(result, underlying_buffer, string_len);
+ OS::MemCopy(result, underlying_buffer, string_len);
return SmartArrayPointer<char>(result);
}
@@ -3295,10 +3439,11 @@
void HGraph::MergeRemovableSimulates() {
+ ZoneList<HSimulate*> mergelist(2, zone());
for (int i = 0; i < blocks()->length(); ++i) {
HBasicBlock* block = blocks()->at(i);
- // Always reset the folding candidate at the start of a block.
- HSimulate* folding_candidate = NULL;
+ // Make sure the merge list is empty at the start of a block.
+ ASSERT(mergelist.is_empty());
// Nasty heuristic: Never remove the first simulate in a block. This
// just so happens to have a beneficial effect on register allocation.
bool first = true;
@@ -3309,33 +3454,38 @@
// in the outer environment.
// (Before each HEnterInlined, there is a non-foldable HSimulate
// anyway, so we get the barrier in the other direction for free.)
- if (folding_candidate != NULL) {
- folding_candidate->DeleteAndReplaceWith(NULL);
+ // Simply remove all accumulated simulates without merging. This
+ // is safe because simulates after instructions with side effects
+ // are never added to the merge list.
+ while (!mergelist.is_empty()) {
+ mergelist.RemoveLast()->DeleteAndReplaceWith(NULL);
}
- folding_candidate = NULL;
continue;
}
- // If we have an HSimulate and a candidate, perform the folding.
+ // Skip the non-simulates and the first simulate.
if (!current->IsSimulate()) continue;
if (first) {
first = false;
continue;
}
HSimulate* current_simulate = HSimulate::cast(current);
- if (folding_candidate != NULL) {
- folding_candidate->MergeInto(current_simulate);
- folding_candidate->DeleteAndReplaceWith(NULL);
- folding_candidate = NULL;
- }
- // Check if the current simulate is a candidate for folding.
- if (current_simulate->previous()->HasObservableSideEffects() &&
- !current_simulate->next()->IsSimulate()) {
+ if ((current_simulate->previous()->HasObservableSideEffects() &&
+ !current_simulate->next()->IsSimulate()) ||
+ !current_simulate->is_candidate_for_removal()) {
+ // This simulate is not suitable for folding.
+ // Fold the ones accumulated so far.
+ current_simulate->MergeWith(&mergelist);
continue;
+ } else {
+ // Accumulate this simulate for folding later on.
+ mergelist.Add(current_simulate, zone());
}
- if (!current_simulate->is_candidate_for_removal()) {
- continue;
- }
- folding_candidate = current_simulate;
+ }
+
+ if (!mergelist.is_empty()) {
+ // Merge the accumulated simulates at the end of the block.
+ HSimulate* last = mergelist.RemoveLast();
+ last->MergeWith(&mergelist);
}
}
}
@@ -4193,8 +4343,6 @@
void HGraph::GlobalValueNumbering() {
// Perform common subexpression elimination and loop-invariant code motion.
if (FLAG_use_gvn) {
- // We use objects' raw addresses for identification, so they must not move.
- Heap::RelocationLock relocation_lock(isolate()->heap());
HPhase phase("H_Global value numbering", this);
HGlobalValueNumberer gvn(this, info());
bool removed_side_effects = gvn.Analyze();
@@ -5977,7 +6125,8 @@
static bool IsFastLiteral(Handle<JSObject> boilerplate,
int max_depth,
int* max_properties,
- int* total_size) {
+ int* data_size,
+ int* pointer_size) {
ASSERT(max_depth >= 0 && *max_properties >= 0);
if (max_depth == 0) return false;
@@ -5986,7 +6135,7 @@
if (elements->length() > 0 &&
elements->map() != isolate->heap()->fixed_cow_array_map()) {
if (boilerplate->HasFastDoubleElements()) {
- *total_size += FixedDoubleArray::SizeFor(elements->length());
+ *data_size += FixedDoubleArray::SizeFor(elements->length());
} else if (boilerplate->HasFastObjectElements()) {
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
int length = elements->length();
@@ -5998,12 +6147,13 @@
if (!IsFastLiteral(value_object,
max_depth - 1,
max_properties,
- total_size)) {
+ data_size,
+ pointer_size)) {
return false;
}
}
}
- *total_size += FixedArray::SizeFor(length);
+ *pointer_size += FixedArray::SizeFor(length);
} else {
return false;
}
@@ -6022,14 +6172,15 @@
if (!IsFastLiteral(value_object,
max_depth - 1,
max_properties,
- total_size)) {
+ data_size,
+ pointer_size)) {
return false;
}
}
}
}
- *total_size += boilerplate->map()->instance_size();
+ *pointer_size += boilerplate->map()->instance_size();
return true;
}
@@ -6043,34 +6194,41 @@
HInstruction* literal;
// Check whether to use fast or slow deep-copying for boilerplate.
- int total_size = 0;
- int max_properties = HFastLiteral::kMaxLiteralProperties;
- Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()),
- isolate());
- if (boilerplate->IsJSObject() &&
- IsFastLiteral(Handle<JSObject>::cast(boilerplate),
- HFastLiteral::kMaxLiteralDepth,
+ int data_size = 0;
+ int pointer_size = 0;
+ int max_properties = kMaxFastLiteralProperties;
+ Handle<Object> original_boilerplate(closure->literals()->get(
+ expr->literal_index()), isolate());
+ if (original_boilerplate->IsJSObject() &&
+ IsFastLiteral(Handle<JSObject>::cast(original_boilerplate),
+ kMaxFastLiteralDepth,
&max_properties,
- &total_size)) {
- Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
- literal = new(zone()) HFastLiteral(context,
- boilerplate_object,
- total_size,
- expr->literal_index(),
- expr->depth(),
- DONT_TRACK_ALLOCATION_SITE);
+ &data_size,
+ &pointer_size)) {
+ Handle<JSObject> original_boilerplate_object =
+ Handle<JSObject>::cast(original_boilerplate);
+ Handle<JSObject> boilerplate_object =
+ DeepCopy(original_boilerplate_object);
+
+ literal = BuildFastLiteral(context,
+ boilerplate_object,
+ original_boilerplate_object,
+ data_size,
+ pointer_size,
+ DONT_TRACK_ALLOCATION_SITE);
} else {
- literal = new(zone()) HObjectLiteral(context,
- expr->constant_properties(),
- expr->fast_elements(),
- expr->literal_index(),
- expr->depth(),
- expr->has_function());
+ literal = AddInstruction(
+ new(zone()) HObjectLiteral(context,
+ expr->constant_properties(),
+ expr->fast_elements(),
+ expr->literal_index(),
+ expr->depth(),
+ expr->has_function()));
}
// The object is expected in the bailout environment during computation
// of the property values and is the value of the entire expression.
- PushAndAdd(literal);
+ Push(literal);
expr->CalculateEmitStore(zone());
@@ -6167,9 +6325,10 @@
}
}
- Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate);
+ Handle<JSObject> original_boilerplate_object =
+ Handle<JSObject>::cast(raw_boilerplate);
ElementsKind boilerplate_elements_kind =
- Handle<JSObject>::cast(boilerplate)->GetElementsKind();
+ Handle<JSObject>::cast(original_boilerplate_object)->GetElementsKind();
// TODO(mvstanton): This heuristic is only a temporary solution. In the
// end, we want to quit creating allocation site info after a certain number
@@ -6178,33 +6337,38 @@
boilerplate_elements_kind);
// Check whether to use fast or slow deep-copying for boilerplate.
- int total_size = 0;
- int max_properties = HFastLiteral::kMaxLiteralProperties;
- if (IsFastLiteral(boilerplate,
- HFastLiteral::kMaxLiteralDepth,
+ int data_size = 0;
+ int pointer_size = 0;
+ int max_properties = kMaxFastLiteralProperties;
+ if (IsFastLiteral(original_boilerplate_object,
+ kMaxFastLiteralDepth,
&max_properties,
- &total_size)) {
+ &data_size,
+ &pointer_size)) {
if (mode == TRACK_ALLOCATION_SITE) {
- total_size += AllocationSiteInfo::kSize;
+ pointer_size += AllocationSiteInfo::kSize;
}
- literal = new(zone()) HFastLiteral(context,
- boilerplate,
- total_size,
- expr->literal_index(),
- expr->depth(),
- mode);
+
+ Handle<JSObject> boilerplate_object = DeepCopy(original_boilerplate_object);
+ literal = BuildFastLiteral(context,
+ boilerplate_object,
+ original_boilerplate_object,
+ data_size,
+ pointer_size,
+ mode);
} else {
- literal = new(zone()) HArrayLiteral(context,
- boilerplate,
- length,
- expr->literal_index(),
- expr->depth(),
- mode);
+ literal = AddInstruction(
+ new(zone()) HArrayLiteral(context,
+ original_boilerplate_object,
+ length,
+ expr->literal_index(),
+ expr->depth(),
+ mode));
}
// The array is expected in the bailout environment during computation
// of the property values and is the value of the entire expression.
- PushAndAdd(literal);
+ Push(literal);
HLoadElements* elements = NULL;
@@ -6420,8 +6584,9 @@
}
AddInstruction(new(zone()) HCheckNonSmi(object));
+
HInstruction* typecheck =
- AddInstruction(HCheckInstanceType::NewIsJSArray(object, zone()));
+ AddInstruction(new(zone()) HCheckMaps(object, types, zone()));
HInstruction* instr =
HLoadNamedField::NewArrayLength(zone(), object, typecheck);
instr->set_position(expr->position());
@@ -7113,8 +7278,10 @@
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
AddCheckMap(object, map);
- HInstruction* holder_value = AddInstruction(
+ AddInstruction(
new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
+ HValue* holder_value = AddInstruction(
+ new(zone()) HConstant(holder, Representation::Tagged()));
return BuildLoadNamedField(holder_value, holder_map, &lookup);
}
@@ -7990,8 +8157,7 @@
// Parse and allocate variables.
CompilationInfo target_info(target, zone());
Handle<SharedFunctionInfo> target_shared(target->shared());
- if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
- !Scope::Analyze(&target_info)) {
+ if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
if (target_info.isolate()->has_pending_exception()) {
// Parse or scope error, never optimize this function.
SetStackOverflow();
@@ -9942,6 +10108,241 @@
}
+HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
+ HValue* context,
+ Handle<JSObject> boilerplate_object,
+ Handle<JSObject> original_boilerplate_object,
+ int data_size,
+ int pointer_size,
+ AllocationSiteMode mode) {
+ Zone* zone = this->zone();
+ int total_size = data_size + pointer_size;
+
+ NoObservableSideEffectsScope no_effects(this);
+
+ HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
+ // TODO(hpayer): add support for old data space
+ if (FLAG_pretenure_literals &&
+ isolate()->heap()->ShouldGloballyPretenure() &&
+ data_size == 0) {
+ flags = static_cast<HAllocate::Flags>(
+ flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
+ }
+
+ HValue* size_in_bytes =
+ AddInstruction(new(zone) HConstant(total_size,
+ Representation::Integer32()));
+ HInstruction* result =
+ AddInstruction(new(zone) HAllocate(context,
+ size_in_bytes,
+ HType::JSObject(),
+ flags));
+ int offset = 0;
+ BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object, result,
+ &offset, mode);
+ return result;
+}
+
+
+void HOptimizedGraphBuilder::BuildEmitDeepCopy(
+ Handle<JSObject> boilerplate_object,
+ Handle<JSObject> original_boilerplate_object,
+ HInstruction* target,
+ int* offset,
+ AllocationSiteMode mode) {
+ Zone* zone = this->zone();
+ Factory* factory = isolate()->factory();
+
+ HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant(
+ original_boilerplate_object, Representation::Tagged()));
+
+ bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
+ boilerplate_object->map()->CanTrackAllocationSite();
+
+ // Only elements backing stores for non-COW arrays need to be copied.
+ Handle<FixedArrayBase> elements(boilerplate_object->elements());
+ Handle<FixedArrayBase> original_elements(
+ original_boilerplate_object->elements());
+ ElementsKind kind = boilerplate_object->map()->elements_kind();
+
+ // Increase the offset so that subsequent objects end up right after
+ // this object and its backing store.
+ int object_offset = *offset;
+ int object_size = boilerplate_object->map()->instance_size();
+ int elements_size = (elements->length() > 0 &&
+ elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
+ elements->Size() : 0;
+ int elements_offset = *offset + object_size;
+ int inobject_properties = boilerplate_object->map()->inobject_properties();
+ if (create_allocation_site_info) {
+ elements_offset += AllocationSiteInfo::kSize;
+ *offset += AllocationSiteInfo::kSize;
+ }
+
+ *offset += object_size + elements_size;
+
+ HValue* object_elements = BuildCopyObjectHeader(boilerplate_object, target,
+ object_offset, elements_offset, elements_size);
+
+ // Copy in-object properties.
+ HValue* object_properties =
+ AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
+ for (int i = 0; i < inobject_properties; i++) {
+ Handle<Object> value =
+ Handle<Object>(boilerplate_object->InObjectPropertyAt(i),
+ isolate());
+ if (value->IsJSObject()) {
+ Handle<JSObject> value_object = Handle<JSObject>::cast(value);
+ Handle<JSObject> original_value_object = Handle<JSObject>::cast(
+ Handle<Object>(original_boilerplate_object->InObjectPropertyAt(i),
+ isolate()));
+ HInstruction* value_instruction =
+ AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
+ AddInstruction(new(zone) HStoreNamedField(
+ object_properties, factory->unknown_field_string(), value_instruction,
+ true, boilerplate_object->GetInObjectPropertyOffset(i)));
+ BuildEmitDeepCopy(value_object, original_value_object, target,
+ offset, DONT_TRACK_ALLOCATION_SITE);
+ } else {
+ HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
+ value, Representation::Tagged()));
+ AddInstruction(new(zone) HStoreNamedField(
+ object_properties, factory->unknown_field_string(), value_instruction,
+ true, boilerplate_object->GetInObjectPropertyOffset(i)));
+ }
+ }
+
+ // Build Allocation Site Info if desired
+ if (create_allocation_site_info) {
+ HValue* alloc_site =
+ AddInstruction(new(zone) HInnerAllocatedObject(target, JSArray::kSize));
+ Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
+ BuildStoreMap(alloc_site, alloc_site_map);
+ int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset;
+ AddInstruction(new(zone) HStoreNamedField(alloc_site,
+ factory->payload_string(),
+ original_boilerplate,
+ true, alloc_payload_offset));
+ }
+
+ if (object_elements != NULL) {
+ HInstruction* boilerplate_elements = AddInstruction(new(zone) HConstant(
+ elements, Representation::Tagged()));
+
+ int elements_length = elements->length();
+ HValue* object_elements_length =
+ AddInstruction(new(zone) HConstant(
+ elements_length, Representation::Integer32()));
+
+ BuildInitializeElements(object_elements, kind, object_elements_length);
+
+ // Copy elements backing store content.
+ if (elements->IsFixedDoubleArray()) {
+ for (int i = 0; i < elements_length; i++) {
+ HValue* key_constant =
+ AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+ HInstruction* value_instruction =
+ AddInstruction(new(zone) HLoadKeyed(
+ boilerplate_elements, key_constant, NULL, kind));
+ AddInstruction(new(zone) HStoreKeyed(
+ object_elements, key_constant, value_instruction, kind));
+ }
+ } else if (elements->IsFixedArray()) {
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
+ Handle<FixedArray> original_fast_elements =
+ Handle<FixedArray>::cast(original_elements);
+ for (int i = 0; i < elements_length; i++) {
+ Handle<Object> value(fast_elements->get(i), isolate());
+ HValue* key_constant =
+ AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+ if (value->IsJSObject()) {
+ Handle<JSObject> value_object = Handle<JSObject>::cast(value);
+ Handle<JSObject> original_value_object = Handle<JSObject>::cast(
+ Handle<Object>(original_fast_elements->get(i), isolate()));
+ HInstruction* value_instruction =
+ AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
+ AddInstruction(new(zone) HStoreKeyed(
+ object_elements, key_constant, value_instruction, kind));
+ BuildEmitDeepCopy(value_object, original_value_object, target,
+ offset, DONT_TRACK_ALLOCATION_SITE);
+ } else {
+ HInstruction* value_instruction =
+ AddInstruction(new(zone) HLoadKeyed(
+ boilerplate_elements, key_constant, NULL, kind));
+ AddInstruction(new(zone) HStoreKeyed(
+ object_elements, key_constant, value_instruction, kind));
+ }
+ }
+ } else {
+ UNREACHABLE();
+ }
+ }
+}
+
+
+HValue* HOptimizedGraphBuilder::BuildCopyObjectHeader(
+ Handle<JSObject> boilerplate_object,
+ HInstruction* target,
+ int object_offset,
+ int elements_offset,
+ int elements_size) {
+ ASSERT(boilerplate_object->properties()->length() == 0);
+ Zone* zone = this->zone();
+ Factory* factory = isolate()->factory();
+ HValue* result = NULL;
+
+ HValue* object_header =
+ AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
+ Handle<Map> boilerplate_object_map(boilerplate_object->map());
+ BuildStoreMap(object_header, boilerplate_object_map);
+
+ HInstruction* elements;
+ if (elements_size == 0) {
+ Handle<Object> elements_field =
+ Handle<Object>(boilerplate_object->elements(), isolate());
+ elements = AddInstruction(new(zone) HConstant(
+ elements_field, Representation::Tagged()));
+ } else {
+ elements = AddInstruction(new(zone) HInnerAllocatedObject(
+ target, elements_offset));
+ result = elements;
+ }
+ HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField(
+ object_header,
+ factory->elements_field_string(),
+ elements,
+ true, JSObject::kElementsOffset));
+ elements_store->SetGVNFlag(kChangesElementsPointer);
+
+ Handle<Object> properties_field =
+ Handle<Object>(boilerplate_object->properties(), isolate());
+ ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
+ HInstruction* properties = AddInstruction(new(zone) HConstant(
+ properties_field, Representation::None()));
+ AddInstruction(new(zone) HStoreNamedField(object_header,
+ factory->empty_string(),
+ properties,
+ true, JSObject::kPropertiesOffset));
+
+ if (boilerplate_object->IsJSArray()) {
+ Handle<JSArray> boilerplate_array =
+ Handle<JSArray>::cast(boilerplate_object);
+ Handle<Object> length_field =
+ Handle<Object>(boilerplate_array->length(), isolate());
+ HInstruction* length = AddInstruction(new(zone) HConstant(
+ length_field, Representation::None()));
+ HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
+ object_header,
+ factory->length_field_string(),
+ length,
+ true, JSArray::kLengthOffset));
+ length_store->SetGVNFlag(kChangesArrayLengths);
+ }
+
+ return result;
+}
+
+
void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -10583,7 +10984,13 @@
void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
- return Bailout("inlined runtime function: MathSqrt");
+ ASSERT(call->arguments()->length() == 1);
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* value = Pop();
+ HValue* context = environment()->LookupContext();
+ HInstruction* result =
+ HUnaryMathOperation::New(zone(), context, value, kMathSqrt);
+ return ast_context()->ReturnInstruction(result, call->id());
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index ef3679e..3dbca3c 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -260,6 +260,7 @@
HBasicBlock* entry_block() const { return entry_block_; }
HEnvironment* start_environment() const { return start_environment_; }
+ void FinalizeUniqueValueIds();
void InitializeInferredTypes();
void InsertTypeConversions();
void MergeRemovableSimulates();
@@ -865,7 +866,10 @@
class HGraphBuilder {
public:
explicit HGraphBuilder(CompilationInfo* info)
- : info_(info), graph_(NULL), current_block_(NULL) {}
+ : info_(info),
+ graph_(NULL),
+ current_block_(NULL),
+ no_side_effects_scope_count_(0) {}
virtual ~HGraphBuilder() {}
HBasicBlock* current_block() const { return current_block_; }
@@ -891,6 +895,14 @@
HReturn* AddReturn(HValue* value);
+ void IncrementInNoSideEffectsScope() {
+ no_side_effects_scope_count_++;
+ }
+
+ void DecrementInNoSideEffectsScope() {
+ no_side_effects_scope_count_--;
+ }
+
protected:
virtual bool BuildGraph() = 0;
@@ -939,8 +951,8 @@
KeyedAccessStoreMode store_mode,
Representation checked_index_representation = Representation::None());
- HInstruction* BuildStoreMap(HValue* object, HValue* map, BailoutId id);
- HInstruction* BuildStoreMap(HValue* object, Handle<Map> map, BailoutId id);
+ HInstruction* BuildStoreMap(HValue* object, HValue* map);
+ HInstruction* BuildStoreMap(HValue* object, Handle<Map> map);
class CheckBuilder {
public:
@@ -1032,6 +1044,20 @@
bool finished_;
};
+ class NoObservableSideEffectsScope {
+ public:
+ explicit NoObservableSideEffectsScope(HGraphBuilder* builder) :
+ builder_(builder) {
+ builder_->IncrementInNoSideEffectsScope();
+ }
+ ~NoObservableSideEffectsScope() {
+ builder_->DecrementInNoSideEffectsScope();
+ }
+
+ private:
+ HGraphBuilder* builder_;
+ };
+
HValue* BuildNewElementsCapacity(HValue* context,
HValue* old_capacity);
@@ -1042,6 +1068,14 @@
ElementsKind kind,
HValue* capacity);
+ void BuildInitializeElements(HValue* elements,
+ ElementsKind kind,
+ HValue* capacity);
+
+ HValue* BuildAllocateAndInitializeElements(HValue* context,
+ ElementsKind kind,
+ HValue* capacity);
+
HValue* BuildGrowElementsCapacity(HValue* object,
HValue* elements,
ElementsKind kind,
@@ -1062,11 +1096,18 @@
HValue* length,
HValue* capacity);
+ HValue* BuildCloneShallowArray(HContext* context,
+ HValue* boilerplate,
+ AllocationSiteMode mode,
+ ElementsKind kind,
+ int length);
+
private:
HGraphBuilder();
CompilationInfo* info_;
HGraph* graph_;
HBasicBlock* current_block_;
+ int no_side_effects_scope_count_;
};
@@ -1183,6 +1224,11 @@
static const int kUnlimitedMaxInlinedNodes = 10000;
static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
+ // Maximum depth and total number of elements and properties for literal
+ // graphs to be considered for fast deep-copying.
+ static const int kMaxFastLiteralDepth = 3;
+ static const int kMaxFastLiteralProperties = 8;
+
// Simple accessors.
void set_function_state(FunctionState* state) { function_state_ = state; }
@@ -1459,6 +1505,26 @@
HInstruction* BuildThisFunction();
+ HInstruction* BuildFastLiteral(HValue* context,
+ Handle<JSObject> boilerplate_object,
+ Handle<JSObject> original_boilerplate_object,
+ int data_size,
+ int pointer_size,
+ AllocationSiteMode mode);
+
+ void BuildEmitDeepCopy(Handle<JSObject> boilerplat_object,
+ Handle<JSObject> object,
+ HInstruction* result,
+ int* offset,
+ AllocationSiteMode mode);
+
+ MUST_USE_RESULT HValue* BuildCopyObjectHeader(
+ Handle<JSObject> boilerplat_object,
+ HInstruction* target,
+ int object_offset,
+ int elements_offset,
+ int elements_size);
+
void AddCheckPrototypeMaps(Handle<JSObject> holder,
Handle<Map> receiver_map);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index b48906e..32fe6a9 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -2556,9 +2556,9 @@
// Copy the data.
int pc_delta = desc.buffer - buffer_;
int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
- memmove(desc.buffer, buffer_, desc.instr_size);
- memmove(rc_delta + reloc_info_writer.pos(),
- reloc_info_writer.pos(), desc.reloc_size);
+ OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+ OS::MemMove(rc_delta + reloc_info_writer.pos(),
+ reloc_info_writer.pos(), desc.reloc_size);
// Switch buffers.
if (isolate()->assembler_spare_buffer() == NULL &&
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index a3da9af..d1c1fbf 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -1026,6 +1026,13 @@
void movdqa(const Operand& dst, XMMRegister src);
void movdqu(XMMRegister dst, const Operand& src);
void movdqu(const Operand& dst, XMMRegister src);
+ void movdq(bool aligned, XMMRegister dst, const Operand& src) {
+ if (aligned) {
+ movdqa(dst, src);
+ } else {
+ movdqu(dst, src);
+ }
+ }
// Use either movsd or movlpd.
void movdbl(XMMRegister dst, const Operand& src);
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index e861db3..08bc227 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -1810,25 +1810,7 @@
void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
- // Get the loop depth of the stack guard check. This is recorded in
- // a test(eax, depth) instruction right after the call.
- Label stack_check;
- __ mov(ebx, Operand(esp, 0)); // return address
- if (FLAG_debug_code) {
- __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
- __ Assert(equal, "test eax instruction not found after loop stack check");
- }
- __ movzx_b(ebx, Operand(ebx, 1)); // depth
-
- // Get the loop nesting level at which we allow OSR from the
- // unoptimized code and check if we want to do OSR yet. If not we
- // should perform a stack guard check so we can get interrupts while
- // waiting for on-stack replacement.
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
- __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
- __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
- __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
- __ j(greater, &stack_check);
// Pass the function to optimize as the argument to the on-stack
// replacement runtime function.
@@ -1845,23 +1827,6 @@
__ j(not_equal, &skip, Label::kNear);
__ ret(0);
- // Insert a stack guard check so that if we decide not to perform
- // on-stack replacement right away, the function calling this stub can
- // still be interrupted.
- __ bind(&stack_check);
- Label ok;
- ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(masm->isolate());
- __ cmp(esp, Operand::StaticVariable(stack_limit));
- __ j(above_equal, &ok, Label::kNear);
- StackCheckStub stub;
- __ TailCallStub(&stub);
- if (FLAG_debug_code) {
- __ Abort("Unreachable code: returned from tail call.");
- }
- __ bind(&ok);
- __ ret(0);
-
__ bind(&skip);
// Untag the AST id and push it on the stack.
__ SmiUntag(eax);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 9b77c50..05dceb7 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "bootstrapper.h"
+#include "builtins-decls.h"
#include "code-stubs.h"
#include "isolate.h"
#include "jsregexp.h"
@@ -43,6 +44,18 @@
namespace internal {
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { eax, ebx, ecx };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->stack_parameter_count_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -163,9 +176,7 @@
// Get the function info from the stack.
__ mov(edx, Operand(esp, 1 * kPointerSize));
- int map_index = (language_mode_ == CLASSIC_MODE)
- ? Context::FUNCTION_MAP_INDEX
- : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+ int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
// Compute the function map in the current native context and set that
// as the map of the allocated object.
@@ -393,168 +404,6 @@
}
-static void GenerateFastCloneShallowArrayCommon(
- MacroAssembler* masm,
- int length,
- FastCloneShallowArrayStub::Mode mode,
- AllocationSiteMode allocation_site_mode,
- Label* fail) {
- // Registers on entry:
- //
- // ecx: boilerplate literal array.
- ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
- // All sizes here are multiples of kPointerSize.
- int elements_size = 0;
- if (length > 0) {
- elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
- ? FixedDoubleArray::SizeFor(length)
- : FixedArray::SizeFor(length);
- }
- int size = JSArray::kSize;
- int allocation_info_start = size;
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- size += AllocationSiteInfo::kSize;
- }
- size += elements_size;
-
- // Allocate both the JS array and the elements array in one big
- // allocation. This avoids multiple limit checks.
- AllocationFlags flags = TAG_OBJECT;
- if (mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS) {
- flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT | flags);
- }
- __ Allocate(size, eax, ebx, edx, fail, flags);
-
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ mov(FieldOperand(eax, allocation_info_start),
- Immediate(Handle<Map>(masm->isolate()->heap()->
- allocation_site_info_map())));
- __ mov(FieldOperand(eax, allocation_info_start + kPointerSize), ecx);
- }
-
- // Copy the JS array part.
- for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
- if ((i != JSArray::kElementsOffset) || (length == 0)) {
- __ mov(ebx, FieldOperand(ecx, i));
- __ mov(FieldOperand(eax, i), ebx);
- }
- }
-
- if (length > 0) {
- // Get hold of the elements array of the boilerplate and setup the
- // elements pointer in the resulting object.
- __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ lea(edx, Operand(eax, JSArray::kSize + AllocationSiteInfo::kSize));
- } else {
- __ lea(edx, Operand(eax, JSArray::kSize));
- }
- __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
-
- // Copy the elements array.
- if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) {
- for (int i = 0; i < elements_size; i += kPointerSize) {
- __ mov(ebx, FieldOperand(ecx, i));
- __ mov(FieldOperand(edx, i), ebx);
- }
- } else {
- ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
- int i;
- for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
- __ mov(ebx, FieldOperand(ecx, i));
- __ mov(FieldOperand(edx, i), ebx);
- }
- while (i < elements_size) {
- __ fld_d(FieldOperand(ecx, i));
- __ fstp_d(FieldOperand(edx, i));
- i += kDoubleSize;
- }
- ASSERT(i == elements_size);
- }
- }
-}
-
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
- // Stack layout on entry:
- //
- // [esp + kPointerSize]: constant elements.
- // [esp + (2 * kPointerSize)]: literal index.
- // [esp + (3 * kPointerSize)]: literals array.
-
- // Load boilerplate object into ecx and check if we need to create a
- // boilerplate.
- __ mov(ecx, Operand(esp, 3 * kPointerSize));
- __ mov(eax, Operand(esp, 2 * kPointerSize));
- STATIC_ASSERT(kPointerSize == 4);
- STATIC_ASSERT(kSmiTagSize == 1);
- STATIC_ASSERT(kSmiTag == 0);
- __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
- FixedArray::kHeaderSize));
- Factory* factory = masm->isolate()->factory();
- __ cmp(ecx, factory->undefined_value());
- Label slow_case;
- __ j(equal, &slow_case);
-
- FastCloneShallowArrayStub::Mode mode = mode_;
- // ecx is boilerplate object.
- if (mode == CLONE_ANY_ELEMENTS) {
- Label double_elements, check_fast_elements;
- __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset));
- __ CheckMap(ebx, factory->fixed_cow_array_map(),
- &check_fast_elements, DONT_DO_SMI_CHECK);
- GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- __ ret(3 * kPointerSize);
-
- __ bind(&check_fast_elements);
- __ CheckMap(ebx, factory->fixed_array_map(),
- &double_elements, DONT_DO_SMI_CHECK);
- GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- __ ret(3 * kPointerSize);
-
- __ bind(&double_elements);
- mode = CLONE_DOUBLE_ELEMENTS;
- // Fall through to generate the code to handle double elements.
- }
-
- if (FLAG_debug_code) {
- const char* message;
- Handle<Map> expected_map;
- if (mode == CLONE_ELEMENTS) {
- message = "Expected (writable) fixed array";
- expected_map = factory->fixed_array_map();
- } else if (mode == CLONE_DOUBLE_ELEMENTS) {
- message = "Expected (writable) fixed double array";
- expected_map = factory->fixed_double_array_map();
- } else {
- ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
- message = "Expected copy-on-write fixed array";
- expected_map = factory->fixed_cow_array_map();
- }
- __ push(ecx);
- __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
- __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map);
- __ Assert(equal, message);
- __ pop(ecx);
- }
-
- GenerateFastCloneShallowArrayCommon(masm, length_, mode,
- allocation_site_mode_,
- &slow_case);
-
- // Return and remove the on-stack parameters.
- __ ret(3 * kPointerSize);
-
- __ bind(&slow_case);
- __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
// The stub expects its argument on the stack and returns its result in tos_:
// zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
@@ -5076,6 +4925,7 @@
void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CEntryStub::GenerateAheadOfTime(isolate);
StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+ StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
// It is important that the store buffer overflow stubs are generated first.
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
}
@@ -5215,8 +5065,13 @@
// Special handling of out of memory exceptions.
JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
- // Retrieve the pending exception and clear the variable.
+ // Retrieve the pending exception.
__ mov(eax, Operand::StaticVariable(pending_exception_address));
+
+ // See if we just retrieved an OOM exception.
+ JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
+
+ // Clear the pending exception.
__ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
__ mov(Operand::StaticVariable(pending_exception_address), edx);
@@ -7786,9 +7641,7 @@
void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
- ASSERT(!Serializer::enabled());
- bool save_fp_regs = CpuFeatures::IsSupported(SSE2);
- CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
+ CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
__ call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 550c83d..caf808b 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -173,21 +173,94 @@
}
-static void MemCopyWrapper(void* dest, const void* src, size_t size) {
- memcpy(dest, src, size);
+// Helper functions for CreateMemMoveFunction.
+#undef __
+#define __ ACCESS_MASM(masm)
+
+// Keep around global pointers to these objects so that Valgrind won't complain.
+static size_t* medium_handlers = NULL;
+static size_t* small_handlers = NULL;
+
+
+enum Direction { FORWARD, BACKWARD };
+enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
+
+// Expects registers:
+// esi - source, aligned if alignment == ALIGNED
+// edi - destination, always aligned
+// ecx - count (copy size in bytes)
+// edx - loop count (number of 64 byte chunks)
+void MemMoveEmitMainLoop(MacroAssembler* masm,
+ Label* move_last_15,
+ Direction direction,
+ Alignment alignment) {
+ Register src = esi;
+ Register dst = edi;
+ Register count = ecx;
+ Register loop_count = edx;
+ Label loop, move_last_31, move_last_63;
+ __ cmp(loop_count, 0);
+ __ j(equal, &move_last_63);
+ __ bind(&loop);
+ // Main loop. Copy in 64 byte chunks.
+ if (direction == BACKWARD) __ sub(src, Immediate(0x40));
+ __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
+ __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
+ __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
+ __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
+ if (direction == FORWARD) __ add(src, Immediate(0x40));
+ if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
+ __ movdqa(Operand(dst, 0x00), xmm0);
+ __ movdqa(Operand(dst, 0x10), xmm1);
+ __ movdqa(Operand(dst, 0x20), xmm2);
+ __ movdqa(Operand(dst, 0x30), xmm3);
+ if (direction == FORWARD) __ add(dst, Immediate(0x40));
+ __ dec(loop_count);
+ __ j(not_zero, &loop);
+ // At most 63 bytes left to copy.
+ __ bind(&move_last_63);
+ __ test(count, Immediate(0x20));
+ __ j(zero, &move_last_31);
+ if (direction == BACKWARD) __ sub(src, Immediate(0x20));
+ __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
+ __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
+ if (direction == FORWARD) __ add(src, Immediate(0x20));
+ if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
+ __ movdqa(Operand(dst, 0x00), xmm0);
+ __ movdqa(Operand(dst, 0x10), xmm1);
+ if (direction == FORWARD) __ add(dst, Immediate(0x20));
+ // At most 31 bytes left to copy.
+ __ bind(&move_last_31);
+ __ test(count, Immediate(0x10));
+ __ j(zero, move_last_15);
+ if (direction == BACKWARD) __ sub(src, Immediate(0x10));
+ __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
+ if (direction == FORWARD) __ add(src, Immediate(0x10));
+ if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
+ __ movdqa(Operand(dst, 0), xmm0);
+ if (direction == FORWARD) __ add(dst, Immediate(0x10));
}
-OS::MemCopyFunction CreateMemCopyFunction() {
+void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
+ __ pop(esi);
+ __ pop(edi);
+ __ ret(0);
+}
+
+
+#undef __
+#define __ masm.
+
+
+OS::MemMoveFunction CreateMemMoveFunction() {
size_t actual_size;
// Allocate buffer in executable space.
- byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
- &actual_size,
- true));
- if (buffer == NULL) return &MemCopyWrapper;
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
+ if (buffer == NULL) return NULL;
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
- // Generated code is put into a fixed, unmovable, buffer, and not into
+ // Generated code is put into a fixed, unmovable buffer, and not into
// the V8 heap. We can't, and don't, refer to any relocatable addresses
// (e.g. the JavaScript nan-object).
@@ -203,185 +276,369 @@
const int kSourceOffset = 2 * kPointerSize;
const int kSizeOffset = 3 * kPointerSize;
+ // When copying up to this many bytes, use special "small" handlers.
+ const size_t kSmallCopySize = 8;
+ // When copying up to this many bytes, use special "medium" handlers.
+ const size_t kMediumCopySize = 63;
+ // When non-overlapping region of src and dst is less than this,
+ // use a more careful implementation (slightly slower).
+ const size_t kMinMoveDistance = 16;
+ // Note that these values are dictated by the implementation below,
+ // do not just change them and hope things will work!
+
int stack_offset = 0; // Update if we change the stack height.
- if (FLAG_debug_code) {
- __ cmp(Operand(esp, kSizeOffset + stack_offset),
- Immediate(OS::kMinComplexMemCopy));
- Label ok;
- __ j(greater_equal, &ok);
- __ int3();
- __ bind(&ok);
- }
+ Label backward, backward_much_overlap;
+ Label forward_much_overlap, small_size, medium_size, pop_and_return;
+ __ push(edi);
+ __ push(esi);
+ stack_offset += 2 * kPointerSize;
+ Register dst = edi;
+ Register src = esi;
+ Register count = ecx;
+ Register loop_count = edx;
+ __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
+ __ mov(src, Operand(esp, stack_offset + kSourceOffset));
+ __ mov(count, Operand(esp, stack_offset + kSizeOffset));
+
+ __ cmp(dst, src);
+ __ j(equal, &pop_and_return);
+
if (CpuFeatures::IsSupported(SSE2)) {
- CpuFeatureScope enable(&masm, SSE2);
- __ push(edi);
- __ push(esi);
- stack_offset += 2 * kPointerSize;
- Register dst = edi;
- Register src = esi;
- Register count = ecx;
- __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
- __ mov(src, Operand(esp, stack_offset + kSourceOffset));
- __ mov(count, Operand(esp, stack_offset + kSizeOffset));
+ CpuFeatureScope sse2_scope(&masm, SSE2);
+ __ prefetch(Operand(src, 0), 1);
+ __ cmp(count, kSmallCopySize);
+ __ j(below_equal, &small_size);
+ __ cmp(count, kMediumCopySize);
+ __ j(below_equal, &medium_size);
+ __ cmp(dst, src);
+ __ j(above, &backward);
-
- __ movdqu(xmm0, Operand(src, 0));
- __ movdqu(Operand(dst, 0), xmm0);
- __ mov(edx, dst);
- __ and_(edx, 0xF);
- __ neg(edx);
- __ add(edx, Immediate(16));
- __ add(dst, edx);
- __ add(src, edx);
- __ sub(count, edx);
-
- // edi is now aligned. Check if esi is also aligned.
- Label unaligned_source;
- __ test(src, Immediate(0x0F));
- __ j(not_zero, &unaligned_source);
{
- // Copy loop for aligned source and destination.
- __ mov(edx, count);
- Register loop_count = ecx;
- Register count = edx;
- __ shr(loop_count, 5);
- {
- // Main copy loop.
- Label loop;
- __ bind(&loop);
- __ prefetch(Operand(src, 0x20), 1);
- __ movdqa(xmm0, Operand(src, 0x00));
- __ movdqa(xmm1, Operand(src, 0x10));
- __ add(src, Immediate(0x20));
-
- __ movdqa(Operand(dst, 0x00), xmm0);
- __ movdqa(Operand(dst, 0x10), xmm1);
- __ add(dst, Immediate(0x20));
-
- __ dec(loop_count);
- __ j(not_zero, &loop);
- }
-
- // At most 31 bytes to copy.
- Label move_less_16;
- __ test(count, Immediate(0x10));
- __ j(zero, &move_less_16);
- __ movdqa(xmm0, Operand(src, 0));
- __ add(src, Immediate(0x10));
- __ movdqa(Operand(dst, 0), xmm0);
- __ add(dst, Immediate(0x10));
- __ bind(&move_less_16);
-
- // At most 15 bytes to copy. Copy 16 bytes at end of string.
- __ and_(count, 0xF);
- __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
- __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
-
- __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
- __ pop(esi);
- __ pop(edi);
- __ ret(0);
- }
- __ Align(16);
- {
- // Copy loop for unaligned source and aligned destination.
- // If source is not aligned, we can't read it as efficiently.
- __ bind(&unaligned_source);
- __ mov(edx, ecx);
- Register loop_count = ecx;
- Register count = edx;
- __ shr(loop_count, 5);
- {
- // Main copy loop
- Label loop;
- __ bind(&loop);
- __ prefetch(Operand(src, 0x20), 1);
- __ movdqu(xmm0, Operand(src, 0x00));
- __ movdqu(xmm1, Operand(src, 0x10));
- __ add(src, Immediate(0x20));
-
- __ movdqa(Operand(dst, 0x00), xmm0);
- __ movdqa(Operand(dst, 0x10), xmm1);
- __ add(dst, Immediate(0x20));
-
- __ dec(loop_count);
- __ j(not_zero, &loop);
- }
-
- // At most 31 bytes to copy.
- Label move_less_16;
- __ test(count, Immediate(0x10));
- __ j(zero, &move_less_16);
+ // |dst| is a lower address than |src|. Copy front-to-back.
+ Label unaligned_source, move_last_15, skip_last_move;
+ __ mov(eax, src);
+ __ sub(eax, dst);
+ __ cmp(eax, kMinMoveDistance);
+ __ j(below, &forward_much_overlap);
+ // Copy first 16 bytes.
__ movdqu(xmm0, Operand(src, 0));
- __ add(src, Immediate(0x10));
- __ movdqa(Operand(dst, 0), xmm0);
- __ add(dst, Immediate(0x10));
- __ bind(&move_less_16);
-
+ __ movdqu(Operand(dst, 0), xmm0);
+ // Determine distance to alignment: 16 - (dst & 0xF).
+ __ mov(edx, dst);
+ __ and_(edx, 0xF);
+ __ neg(edx);
+ __ add(edx, Immediate(16));
+ __ add(dst, edx);
+ __ add(src, edx);
+ __ sub(count, edx);
+ // dst is now aligned. Main copy loop.
+ __ mov(loop_count, count);
+ __ shr(loop_count, 6);
+ // Check if src is also aligned.
+ __ test(src, Immediate(0xF));
+ __ j(not_zero, &unaligned_source);
+ // Copy loop for aligned source and destination.
+ MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
// At most 15 bytes to copy. Copy 16 bytes at end of string.
- __ and_(count, 0x0F);
+ __ bind(&move_last_15);
+ __ and_(count, 0xF);
+ __ j(zero, &skip_last_move, Label::kNear);
__ movdqu(xmm0, Operand(src, count, times_1, -0x10));
__ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
+ __ bind(&skip_last_move);
+ MemMoveEmitPopAndReturn(&masm);
- __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
- __ pop(esi);
- __ pop(edi);
- __ ret(0);
+ // Copy loop for unaligned source and aligned destination.
+ __ bind(&unaligned_source);
+ MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
+ __ jmp(&move_last_15);
+
+ // Less than kMinMoveDistance offset between dst and src.
+ Label loop_until_aligned, last_15_much_overlap;
+ __ bind(&loop_until_aligned);
+ __ mov_b(eax, Operand(src, 0));
+ __ inc(src);
+ __ mov_b(Operand(dst, 0), eax);
+ __ inc(dst);
+ __ dec(count);
+ __ bind(&forward_much_overlap); // Entry point into this block.
+ __ test(dst, Immediate(0xF));
+ __ j(not_zero, &loop_until_aligned);
+ // dst is now aligned, src can't be. Main copy loop.
+ __ mov(loop_count, count);
+ __ shr(loop_count, 6);
+ MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
+ FORWARD, MOVE_UNALIGNED);
+ __ bind(&last_15_much_overlap);
+ __ and_(count, 0xF);
+ __ j(zero, &pop_and_return);
+ __ cmp(count, kSmallCopySize);
+ __ j(below_equal, &small_size);
+ __ jmp(&medium_size);
}
+ {
+ // |dst| is a higher address than |src|. Copy backwards.
+ Label unaligned_source, move_first_15, skip_last_move;
+ __ bind(&backward);
+ // |dst| and |src| always point to the end of what's left to copy.
+ __ add(dst, count);
+ __ add(src, count);
+ __ mov(eax, dst);
+ __ sub(eax, src);
+ __ cmp(eax, kMinMoveDistance);
+ __ j(below, &backward_much_overlap);
+ // Copy last 16 bytes.
+ __ movdqu(xmm0, Operand(src, -0x10));
+ __ movdqu(Operand(dst, -0x10), xmm0);
+ // Find distance to alignment: dst & 0xF
+ __ mov(edx, dst);
+ __ and_(edx, 0xF);
+ __ sub(dst, edx);
+ __ sub(src, edx);
+ __ sub(count, edx);
+ // dst is now aligned. Main copy loop.
+ __ mov(loop_count, count);
+ __ shr(loop_count, 6);
+ // Check if src is also aligned.
+ __ test(src, Immediate(0xF));
+ __ j(not_zero, &unaligned_source);
+ // Copy loop for aligned source and destination.
+ MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
+ // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
+ __ bind(&move_first_15);
+ __ and_(count, 0xF);
+ __ j(zero, &skip_last_move, Label::kNear);
+ __ sub(src, count);
+ __ sub(dst, count);
+ __ movdqu(xmm0, Operand(src, 0));
+ __ movdqu(Operand(dst, 0), xmm0);
+ __ bind(&skip_last_move);
+ MemMoveEmitPopAndReturn(&masm);
+
+ // Copy loop for unaligned source and aligned destination.
+ __ bind(&unaligned_source);
+ MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
+ __ jmp(&move_first_15);
+
+ // Less than kMinMoveDistance offset between dst and src.
+ Label loop_until_aligned, first_15_much_overlap;
+ __ bind(&loop_until_aligned);
+ __ dec(src);
+ __ dec(dst);
+ __ mov_b(eax, Operand(src, 0));
+ __ mov_b(Operand(dst, 0), eax);
+ __ dec(count);
+ __ bind(&backward_much_overlap); // Entry point into this block.
+ __ test(dst, Immediate(0xF));
+ __ j(not_zero, &loop_until_aligned);
+ // dst is now aligned, src can't be. Main copy loop.
+ __ mov(loop_count, count);
+ __ shr(loop_count, 6);
+ MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
+ BACKWARD, MOVE_UNALIGNED);
+ __ bind(&first_15_much_overlap);
+ __ and_(count, 0xF);
+ __ j(zero, &pop_and_return);
+ // Small/medium handlers expect dst/src to point to the beginning.
+ __ sub(dst, count);
+ __ sub(src, count);
+ __ cmp(count, kSmallCopySize);
+ __ j(below_equal, &small_size);
+ __ jmp(&medium_size);
+ }
+ {
+ // Special handlers for 9 <= copy_size < 64. No assumptions about
+ // alignment or move distance, so all reads must be unaligned and
+ // must happen before any writes.
+ Label f9_16, f17_32, f33_48, f49_63;
+
+ __ bind(&f9_16);
+ __ movdbl(xmm0, Operand(src, 0));
+ __ movdbl(xmm1, Operand(src, count, times_1, -8));
+ __ movdbl(Operand(dst, 0), xmm0);
+ __ movdbl(Operand(dst, count, times_1, -8), xmm1);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f17_32);
+ __ movdqu(xmm0, Operand(src, 0));
+ __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
+ __ movdqu(Operand(dst, 0x00), xmm0);
+ __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f33_48);
+ __ movdqu(xmm0, Operand(src, 0x00));
+ __ movdqu(xmm1, Operand(src, 0x10));
+ __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
+ __ movdqu(Operand(dst, 0x00), xmm0);
+ __ movdqu(Operand(dst, 0x10), xmm1);
+ __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f49_63);
+ __ movdqu(xmm0, Operand(src, 0x00));
+ __ movdqu(xmm1, Operand(src, 0x10));
+ __ movdqu(xmm2, Operand(src, 0x20));
+ __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
+ __ movdqu(Operand(dst, 0x00), xmm0);
+ __ movdqu(Operand(dst, 0x10), xmm1);
+ __ movdqu(Operand(dst, 0x20), xmm2);
+ __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
+ MemMoveEmitPopAndReturn(&masm);
+
+ medium_handlers = new size_t[4];
+ medium_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f9_16.pos();
+ medium_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f17_32.pos();
+ medium_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f33_48.pos();
+ medium_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f49_63.pos();
+
+ __ bind(&medium_size); // Entry point into this block.
+ __ mov(eax, count);
+ __ dec(eax);
+ __ shr(eax, 4);
+ if (FLAG_debug_code) {
+ Label ok;
+ __ cmp(eax, 3);
+ __ j(below_equal, &ok);
+ __ int3();
+ __ bind(&ok);
+ }
+ __ mov(eax, Operand(eax, times_4,
+ reinterpret_cast<intptr_t>(medium_handlers)));
+ __ jmp(eax);
+ }
+ {
+ // Specialized copiers for copy_size <= 8 bytes.
+ Label f0, f1, f2, f3, f4, f5_8;
+ __ bind(&f0);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f1);
+ __ mov_b(eax, Operand(src, 0));
+ __ mov_b(Operand(dst, 0), eax);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f2);
+ __ mov_w(eax, Operand(src, 0));
+ __ mov_w(Operand(dst, 0), eax);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f3);
+ __ mov_w(eax, Operand(src, 0));
+ __ mov_b(edx, Operand(src, 2));
+ __ mov_w(Operand(dst, 0), eax);
+ __ mov_b(Operand(dst, 2), edx);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f4);
+ __ mov(eax, Operand(src, 0));
+ __ mov(Operand(dst, 0), eax);
+ MemMoveEmitPopAndReturn(&masm);
+
+ __ bind(&f5_8);
+ __ mov(eax, Operand(src, 0));
+ __ mov(edx, Operand(src, count, times_1, -4));
+ __ mov(Operand(dst, 0), eax);
+ __ mov(Operand(dst, count, times_1, -4), edx);
+ MemMoveEmitPopAndReturn(&masm);
+
+ small_handlers = new size_t[9];
+ small_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f0.pos();
+ small_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f1.pos();
+ small_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f2.pos();
+ small_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f3.pos();
+ small_handlers[4] = reinterpret_cast<intptr_t>(buffer) + f4.pos();
+ small_handlers[5] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+ small_handlers[6] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+ small_handlers[7] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+ small_handlers[8] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+
+ __ bind(&small_size); // Entry point into this block.
+ if (FLAG_debug_code) {
+ Label ok;
+ __ cmp(count, 8);
+ __ j(below_equal, &ok);
+ __ int3();
+ __ bind(&ok);
+ }
+ __ mov(eax, Operand(count, times_4,
+ reinterpret_cast<intptr_t>(small_handlers)));
+ __ jmp(eax);
+ }
} else {
- // SSE2 not supported. Unlikely to happen in practice.
- __ push(edi);
- __ push(esi);
- stack_offset += 2 * kPointerSize;
- __ cld();
- Register dst = edi;
- Register src = esi;
- Register count = ecx;
- __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
- __ mov(src, Operand(esp, stack_offset + kSourceOffset));
- __ mov(count, Operand(esp, stack_offset + kSizeOffset));
+ // No SSE2.
+ Label forward;
+ __ cmp(count, 0);
+ __ j(equal, &pop_and_return);
+ __ cmp(dst, src);
+ __ j(above, &backward);
+ __ jmp(&forward);
+ {
+ // Simple forward copier.
+ Label forward_loop_1byte, forward_loop_4byte;
+ __ bind(&forward_loop_4byte);
+ __ mov(eax, Operand(src, 0));
+ __ sub(count, Immediate(4));
+ __ add(src, Immediate(4));
+ __ mov(Operand(dst, 0), eax);
+ __ add(dst, Immediate(4));
+ __ bind(&forward); // Entry point.
+ __ cmp(count, 3);
+ __ j(above, &forward_loop_4byte);
+ __ bind(&forward_loop_1byte);
+ __ cmp(count, 0);
+ __ j(below_equal, &pop_and_return);
+ __ mov_b(eax, Operand(src, 0));
+ __ dec(count);
+ __ inc(src);
+ __ mov_b(Operand(dst, 0), eax);
+ __ inc(dst);
+ __ jmp(&forward_loop_1byte);
+ }
+ {
+ // Simple backward copier.
+ Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
+ __ bind(&backward);
+ __ add(src, count);
+ __ add(dst, count);
+ __ cmp(count, 3);
+ __ j(below_equal, &entry_shortcut);
- // Copy the first word.
- __ mov(eax, Operand(src, 0));
- __ mov(Operand(dst, 0), eax);
-
- // Increment src,dstso that dst is aligned.
- __ mov(edx, dst);
- __ and_(edx, 0x03);
- __ neg(edx);
- __ add(edx, Immediate(4)); // edx = 4 - (dst & 3)
- __ add(dst, edx);
- __ add(src, edx);
- __ sub(count, edx);
- // edi is now aligned, ecx holds number of remaning bytes to copy.
-
- __ mov(edx, count);
- count = edx;
- __ shr(ecx, 2); // Make word count instead of byte count.
- __ rep_movs();
-
- // At most 3 bytes left to copy. Copy 4 bytes at end of string.
- __ and_(count, 3);
- __ mov(eax, Operand(src, count, times_1, -4));
- __ mov(Operand(dst, count, times_1, -4), eax);
-
- __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
- __ pop(esi);
- __ pop(edi);
- __ ret(0);
+ __ bind(&backward_loop_4byte);
+ __ sub(src, Immediate(4));
+ __ sub(count, Immediate(4));
+ __ mov(eax, Operand(src, 0));
+ __ sub(dst, Immediate(4));
+ __ mov(Operand(dst, 0), eax);
+ __ cmp(count, 3);
+ __ j(above, &backward_loop_4byte);
+ __ bind(&backward_loop_1byte);
+ __ cmp(count, 0);
+ __ j(below_equal, &pop_and_return);
+ __ bind(&entry_shortcut);
+ __ dec(src);
+ __ dec(count);
+ __ mov_b(eax, Operand(src, 0));
+ __ dec(dst);
+ __ mov_b(Operand(dst, 0), eax);
+ __ jmp(&backward_loop_1byte);
+ }
}
+ __ bind(&pop_and_return);
+ MemMoveEmitPopAndReturn(&masm);
+
CodeDesc desc;
masm.GetCode(&desc);
ASSERT(!RelocInfo::RequiresRelocation(desc));
-
CPU::FlushICache(buffer, actual_size);
OS::ProtectCode(buffer, actual_size);
- return FUNCTION_CAST<OS::MemCopyFunction>(buffer);
+ return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
}
+
#undef __
// -------------------------------------------------------------------------
diff --git a/src/ia32/cpu-ia32.cc b/src/ia32/cpu-ia32.cc
index 9eabb2a..2d83cab 100644
--- a/src/ia32/cpu-ia32.cc
+++ b/src/ia32/cpu-ia32.cc
@@ -79,6 +79,8 @@
// instead
// __asm { int 3 }
__debugbreak();
+#elif defined(__native_client__)
+ asm("hlt");
#else
asm("int $3");
#endif
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index 8cdcf99..f043622 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -90,9 +90,9 @@
Factory* factory = isolate->factory();
Handle<ByteArray> new_reloc =
factory->NewByteArray(reloc_length + padding, TENURED);
- memcpy(new_reloc->GetDataStartAddress() + padding,
- code->relocation_info()->GetDataStartAddress(),
- reloc_length);
+ OS::MemCopy(new_reloc->GetDataStartAddress() + padding,
+ code->relocation_info()->GetDataStartAddress(),
+ reloc_length);
// Create a relocation writer to write the comments in the padding
// space. Use position 0 for everything to ensure short encoding.
RelocInfoWriter reloc_info_writer(
@@ -177,7 +177,8 @@
// Move the relocation info to the beginning of the byte array.
int new_reloc_size = reloc_end_address - reloc_info_writer.pos();
- memmove(code->relocation_start(), reloc_info_writer.pos(), new_reloc_size);
+ OS::MemMove(
+ code->relocation_start(), reloc_info_writer.pos(), new_reloc_size);
// The relocation info is in place, update the size.
reloc_info->set_length(new_reloc_size);
@@ -211,41 +212,39 @@
static const byte kJnsInstruction = 0x79;
-static const byte kJnsOffset = 0x13;
+static const byte kJnsOffset = 0x11;
static const byte kCallInstruction = 0xe8;
static const byte kNopByteOne = 0x66;
static const byte kNopByteTwo = 0x90;
+// The back edge bookkeeping code matches the pattern:
+//
+// sub <profiling_counter>, <delta>
+// jns ok
+// call <interrupt stub>
+// ok:
+//
+// The patched back edge looks like this:
+//
+// sub <profiling_counter>, <delta> ;; Not changed
+// nop
+// nop
+// call <on-stack replacment>
+// ok:
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ // Turn the jump into nops.
Address call_target_address = pc_after - kIntSize;
- ASSERT_EQ(check_code->entry(),
- Assembler::target_address_at(call_target_address));
- // The back edge bookkeeping code matches the pattern:
- //
- // sub <profiling_counter>, <delta>
- // jns ok
- // call <stack guard>
- // test eax, <loop nesting depth>
- // ok: ...
- //
- // We will patch away the branch so the code is:
- //
- // sub <profiling_counter>, <delta> ;; Not changed
- // nop
- // nop
- // call <on-stack replacment>
- // test eax, <loop nesting depth>
- // ok:
-
- ASSERT_EQ(kJnsInstruction, *(call_target_address - 3));
- ASSERT_EQ(kJnsOffset, *(call_target_address - 2));
- ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
*(call_target_address - 3) = kNopByteOne;
*(call_target_address - 2) = kNopByteTwo;
+ // Replace the call address.
Assembler::set_target_address_at(call_target_address,
replacement_code->entry());
@@ -254,29 +253,50 @@
}
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ // Restore the original jump.
Address call_target_address = pc_after - kIntSize;
- ASSERT_EQ(replacement_code->entry(),
- Assembler::target_address_at(call_target_address));
-
- // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to
- // restore the conditional branch.
- ASSERT_EQ(kNopByteOne, *(call_target_address - 3));
- ASSERT_EQ(kNopByteTwo, *(call_target_address - 2));
- ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
*(call_target_address - 3) = kJnsInstruction;
*(call_target_address - 2) = kJnsOffset;
+ // Restore the original call address.
Assembler::set_target_address_at(call_target_address,
- check_code->entry());
+ interrupt_code->entry());
- check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
- unoptimized_code, call_target_address, check_code);
+ interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+ unoptimized_code, call_target_address, interrupt_code);
}
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ Address call_target_address = pc_after - kIntSize;
+ ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
+ if (*(call_target_address - 3) == kNopByteOne) {
+ ASSERT_EQ(replacement_code->entry(),
+ Assembler::target_address_at(call_target_address));
+ ASSERT_EQ(kNopByteTwo, *(call_target_address - 2));
+ return true;
+ } else {
+ ASSERT_EQ(interrupt_code->entry(),
+ Assembler::target_address_at(call_target_address));
+ ASSERT_EQ(kJnsInstruction, *(call_target_address - 3));
+ ASSERT_EQ(kJnsOffset, *(call_target_address - 2));
+ return false;
+ }
+}
+#endif // DEBUG
+
+
static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
ByteArray* translations = data->TranslationByteArray();
int length = data->DeoptCount();
diff --git a/src/ia32/frames-ia32.h b/src/ia32/frames-ia32.h
index c59b166..6223748 100644
--- a/src/ia32/frames-ia32.h
+++ b/src/ia32/frames-ia32.h
@@ -60,18 +60,6 @@
// ----------------------------------------------------
-class StackHandlerConstants : public AllStatic {
- public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kCodeOffset = 1 * kPointerSize;
- static const int kStateOffset = 2 * kPointerSize;
- static const int kContextOffset = 3 * kPointerSize;
- static const int kFPOffset = 4 * kPointerSize;
-
- static const int kSize = kFPOffset + kPointerSize;
-};
-
-
class EntryFrameConstants : public AllStatic {
public:
static const int kCallerFPOffset = -6 * kPointerSize;
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index efbdf13..19989b1 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -164,6 +164,8 @@
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
if (locals_count == 1) {
__ push(Immediate(isolate()->factory()->undefined_value()));
} else if (locals_count > 1) {
@@ -351,13 +353,6 @@
// the deoptimization input data found in the optimized code.
RecordBackEdge(stmt->OsrEntryId());
- // Loop stack checks can be patched to perform on-stack replacement. In
- // order to decide whether or not to perform OSR we embed the loop depth
- // in a test instruction after the call so we can extract it from the OSR
- // builtin.
- ASSERT(loop_depth() > 0);
- __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
-
EmitProfilingCounterReset();
__ bind(&ok);
@@ -1214,7 +1209,7 @@
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->language_mode());
+ FastNewClosureStub stub(info->language_mode(), info->is_generator());
__ push(Immediate(info));
__ CallStub(&stub);
} else {
@@ -1670,24 +1665,33 @@
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
- __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
- __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
- __ push(Immediate(Smi::FromInt(expr->literal_index())));
- __ push(Immediate(constant_elements));
Heap* heap = isolate()->heap();
if (has_constant_fast_elements &&
constant_elements_values->map() == heap->fixed_cow_array_map()) {
// If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
// change, so it's possible to specialize the stub in advance.
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
+ __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+ __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
+ __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
+ __ mov(ecx, Immediate(constant_elements));
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
DONT_TRACK_ALLOCATION_SITE,
length);
__ CallStub(&stub);
} else if (expr->depth() > 1) {
+ __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
+ __ push(Immediate(Smi::FromInt(expr->literal_index())));
+ __ push(Immediate(constant_elements));
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
- } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ } else if (Serializer::enabled() ||
+ length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
+ __ push(Immediate(Smi::FromInt(expr->literal_index())));
+ __ push(Immediate(constant_elements));
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -1704,6 +1708,10 @@
allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
}
+ __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+ __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
+ __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
+ __ mov(ecx, Immediate(constant_elements));
FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
__ CallStub(&stub);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 4d23aef..1dcad04 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -135,7 +135,7 @@
// issues when the stack allocated buffer goes out of scope.
size_t length = builder.position();
Vector<char> copy = Vector<char>::New(length + 1);
- memcpy(copy.start(), builder.Finalize(), copy.length());
+ OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
masm()->RecordComment(copy.start());
}
@@ -366,7 +366,20 @@
Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
}
}
+
+ if (!CpuFeatures::IsSupported(SSE2)) {
+ FlushX87StackIfNecessary(instr);
+ }
+
instr->CompileToNative(this);
+
+ if (!CpuFeatures::IsSupported(SSE2)) {
+ ASSERT(!instr->HasDoubleRegisterResult() || x87_stack_depth_ == 1);
+
+ if (FLAG_debug_code && FLAG_enable_slow_asserts) {
+ __ VerifyX87StackDepth(x87_stack_depth_);
+ }
+ }
}
}
EnsureSpaceForLazyDeopt();
@@ -521,6 +534,52 @@
}
+void LCodeGen::ReadX87Operand(Operand dst) {
+ ASSERT(x87_stack_depth_ == 1);
+ __ fst_d(dst);
+}
+
+
+void LCodeGen::PushX87DoubleOperand(Operand src) {
+ ASSERT(x87_stack_depth_ == 0);
+ x87_stack_depth_++;
+ __ fld_d(src);
+}
+
+
+void LCodeGen::PushX87FloatOperand(Operand src) {
+ ASSERT(x87_stack_depth_ == 0);
+ x87_stack_depth_++;
+ __ fld_s(src);
+}
+
+
+void LCodeGen::PopX87() {
+ ASSERT(x87_stack_depth_ == 1);
+ x87_stack_depth_--;
+ __ fstp(0);
+}
+
+
+void LCodeGen::CurrentInstructionReturnsX87Result() {
+ ASSERT(x87_stack_depth_ <= 1);
+ if (x87_stack_depth_ == 0) {
+ x87_stack_depth_ = 1;
+ }
+}
+
+
+void LCodeGen::FlushX87StackIfNecessary(LInstruction* instr) {
+ if (x87_stack_depth_ > 0) {
+ if ((instr->ClobbersDoubleRegisters() ||
+ instr->HasDoubleRegisterResult()) &&
+ !instr->HasDoubleRegisterInput()) {
+ PopX87();
+ }
+ }
+}
+
+
Register LCodeGen::ToRegister(LOperand* op) const {
ASSERT(op->IsRegister());
return ToRegister(op->index());
@@ -846,6 +905,8 @@
void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered());
+ // It's an error to deoptimize with the x87 fp stack in use.
+ ASSERT(x87_stack_depth_ == 0);
int id = environment->deoptimization_index();
ASSERT(info()->IsOptimizing() || info()->IsStub());
Deoptimizer::BailoutType bailout_type = info()->IsStub()
@@ -858,8 +919,8 @@
return;
}
- if (FLAG_deopt_every_n_times != 0) {
- Handle<SharedFunctionInfo> shared(info_->shared_info());
+ if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+ Handle<SharedFunctionInfo> shared(info()->shared_info());
Label no_deopt;
__ pushfd();
__ push(eax);
@@ -1689,40 +1750,46 @@
void LCodeGen::DoConstantD(LConstantD* instr) {
- ASSERT(instr->result()->IsDoubleRegister());
- XMMRegister res = ToDoubleRegister(instr->result());
double v = instr->value();
- // Use xor to produce +0.0 in a fast and compact way, but avoid to
- // do so if the constant is -0.0.
- if (BitCast<uint64_t, double>(v) == 0) {
- __ xorps(res, res);
+ uint64_t int_val = BitCast<uint64_t, double>(v);
+ int32_t lower = static_cast<int32_t>(int_val);
+ int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+
+ if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ __ push(Immediate(lower));
+ __ push(Immediate(upper));
+ PushX87DoubleOperand(Operand(esp, 0));
+ __ add(Operand(esp), Immediate(kDoubleSize));
+ CurrentInstructionReturnsX87Result();
} else {
- Register temp = ToRegister(instr->temp());
- uint64_t int_val = BitCast<uint64_t, double>(v);
- int32_t lower = static_cast<int32_t>(int_val);
- int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
- if (CpuFeatures::IsSupported(SSE4_1)) {
- CpuFeatureScope scope1(masm(), SSE2);
- CpuFeatureScope scope2(masm(), SSE4_1);
- if (lower != 0) {
- __ Set(temp, Immediate(lower));
- __ movd(res, Operand(temp));
- __ Set(temp, Immediate(upper));
- __ pinsrd(res, Operand(temp), 1);
- } else {
- __ xorps(res, res);
- __ Set(temp, Immediate(upper));
- __ pinsrd(res, Operand(temp), 1);
- }
+ CpuFeatureScope scope1(masm(), SSE2);
+ ASSERT(instr->result()->IsDoubleRegister());
+ XMMRegister res = ToDoubleRegister(instr->result());
+ if (int_val == 0) {
+ __ xorps(res, res);
} else {
- CpuFeatureScope scope(masm(), SSE2);
- __ Set(temp, Immediate(upper));
- __ movd(res, Operand(temp));
- __ psllq(res, 32);
- if (lower != 0) {
- __ Set(temp, Immediate(lower));
- __ movd(xmm0, Operand(temp));
- __ por(res, xmm0);
+ Register temp = ToRegister(instr->temp());
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope scope2(masm(), SSE4_1);
+ if (lower != 0) {
+ __ Set(temp, Immediate(lower));
+ __ movd(res, Operand(temp));
+ __ Set(temp, Immediate(upper));
+ __ pinsrd(res, Operand(temp), 1);
+ } else {
+ __ xorps(res, res);
+ __ Set(temp, Immediate(upper));
+ __ pinsrd(res, Operand(temp), 1);
+ }
+ } else {
+ __ Set(temp, Immediate(upper));
+ __ movd(res, Operand(temp));
+ __ psllq(res, 32);
+ if (lower != 0) {
+ __ Set(temp, Immediate(lower));
+ __ movd(xmm0, Operand(temp));
+ __ por(res, xmm0);
+ }
}
}
}
@@ -1951,6 +2018,9 @@
break;
case Token::DIV:
__ divsd(left, right);
+ // Don't delete this mov. It may improve performance on some CPUs,
+ // when there is a mulsd depending on the result
+ __ movaps(left, left);
break;
case Token::MOD: {
// Pass two doubles as arguments on the stack.
@@ -3158,16 +3228,16 @@
__ movss(result, operand);
__ cvtss2sd(result, result);
} else {
- __ fld_s(operand);
- HandleX87FPReturnValue(instr);
+ PushX87FloatOperand(operand);
+ CurrentInstructionReturnsX87Result();
}
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(masm(), SSE2);
__ movdbl(ToDoubleRegister(instr->result()), operand);
} else {
- __ fld_d(operand);
- HandleX87FPReturnValue(instr);
+ PushX87DoubleOperand(operand);
+ CurrentInstructionReturnsX87Result();
}
} else {
Register result(ToRegister(instr->result()));
@@ -3212,29 +3282,6 @@
}
-void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) {
- if (IsX87TopOfStack(instr->result())) {
- // Return value is already on stack. If the value has no uses, then
- // pop it off the FP stack. Otherwise, make sure that there are enough
- // copies of the value on the stack to feed all of the usages, e.g.
- // when the following instruction uses the return value in multiple
- // inputs.
- int count = instr->hydrogen_value()->UseCount();
- if (count == 0) {
- __ fstp(0);
- } else {
- count--;
- ASSERT(count <= 7);
- while (count-- > 0) {
- __ fld(0);
- }
- }
- } else {
- __ fstp_d(ToOperand(instr->result()));
- }
-}
-
-
void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
if (instr->hydrogen()->RequiresHoleCheck()) {
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
@@ -3261,8 +3308,8 @@
XMMRegister result = ToDoubleRegister(instr->result());
__ movdbl(result, double_load_operand);
} else {
- __ fld_d(double_load_operand);
- HandleX87FPReturnValue(instr);
+ PushX87DoubleOperand(double_load_operand);
+ CurrentInstructionReturnsX87Result();
}
}
@@ -3598,7 +3645,7 @@
}
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
Register input_reg = ToRegister(instr->value());
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
factory()->heap_number_map());
@@ -3651,7 +3698,7 @@
}
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
Register input_reg = ToRegister(instr->value());
__ test(input_reg, Operand(input_reg));
Label is_positive;
@@ -3663,19 +3710,18 @@
}
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
// Class for deferred case.
class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
public:
- DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
- LUnaryMathOperation* instr)
+ DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
}
virtual LInstruction* instr() { return instr_; }
private:
- LUnaryMathOperation* instr_;
+ LMathAbs* instr_;
};
ASSERT(instr->value()->Equals(instr->result()));
@@ -3702,7 +3748,7 @@
}
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
CpuFeatureScope scope(masm(), SSE2);
XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result());
@@ -3828,7 +3874,7 @@
}
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
CpuFeatureScope scope(masm(), SSE2);
XMMRegister input_reg = ToDoubleRegister(instr->value());
ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
@@ -3981,7 +4027,7 @@
}
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
CpuFeatureScope scope(masm(), SSE2);
ASSERT(instr->value()->Equals(instr->result()));
XMMRegister input_reg = ToDoubleRegister(instr->value());
@@ -4024,7 +4070,7 @@
}
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::TAN,
TranscendentalCacheStub::UNTAGGED);
@@ -4032,7 +4078,7 @@
}
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
@@ -4040,7 +4086,7 @@
}
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
@@ -4048,36 +4094,6 @@
}
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
- switch (instr->op()) {
- case kMathAbs:
- DoMathAbs(instr);
- break;
- case kMathFloor:
- DoMathFloor(instr);
- break;
- case kMathSqrt:
- DoMathSqrt(instr);
- break;
- case kMathCos:
- DoMathCos(instr);
- break;
- case kMathSin:
- DoMathSin(instr);
- break;
- case kMathTan:
- DoMathTan(instr);
- break;
- case kMathLog:
- DoMathLog(instr);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->function()).is(edi));
@@ -4311,12 +4327,21 @@
0,
instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- CpuFeatureScope scope(masm(), SSE2);
- __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
- __ movss(operand, xmm0);
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ CpuFeatureScope scope(masm(), SSE2);
+ __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
+ __ movss(operand, xmm0);
+ } else {
+ __ fld(0);
+ __ fstp_s(operand);
+ }
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- CpuFeatureScope scope(masm(), SSE2);
- __ movdbl(operand, ToDoubleRegister(instr->value()));
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ CpuFeatureScope scope(masm(), SSE2);
+ __ movdbl(operand, ToDoubleRegister(instr->value()));
+ } else {
+ __ fst_d(operand);
+ }
} else {
Register value = ToRegister(instr->value());
switch (elements_kind) {
@@ -4351,21 +4376,8 @@
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
- CpuFeatureScope scope(masm(), SSE2);
- XMMRegister value = ToDoubleRegister(instr->value());
-
- if (instr->NeedsCanonicalization()) {
- Label have_value;
-
- __ ucomisd(value, value);
- __ j(parity_odd, &have_value); // NaN.
-
- ExternalReference canonical_nan_reference =
- ExternalReference::address_of_canonical_non_hole_nan();
- __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
- __ bind(&have_value);
- }
-
+ ExternalReference canonical_nan_reference =
+ ExternalReference::address_of_canonical_non_hole_nan();
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
@@ -4373,7 +4385,68 @@
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
- __ movdbl(double_store_operand, value);
+
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ CpuFeatureScope scope(masm(), SSE2);
+ XMMRegister value = ToDoubleRegister(instr->value());
+
+ if (instr->NeedsCanonicalization()) {
+ Label have_value;
+
+ __ ucomisd(value, value);
+ __ j(parity_odd, &have_value); // NaN.
+
+ __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
+ __ bind(&have_value);
+ }
+
+ __ movdbl(double_store_operand, value);
+ } else {
+ // Can't use SSE2 in the serializer
+ if (instr->hydrogen()->IsConstantHoleStore()) {
+ // This means we should store the (double) hole. No floating point
+ // registers required.
+ double nan_double = FixedDoubleArray::hole_nan_as_double();
+ uint64_t int_val = BitCast<uint64_t, double>(nan_double);
+ int32_t lower = static_cast<int32_t>(int_val);
+ int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+
+ __ mov(double_store_operand, Immediate(lower));
+ Operand double_store_operand2 = BuildFastArrayOperand(
+ instr->elements(),
+ instr->key(),
+ instr->hydrogen()->key()->representation(),
+ FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag + kPointerSize,
+ instr->additional_index());
+ __ mov(double_store_operand2, Immediate(upper));
+ } else {
+ Label no_special_nan_handling;
+ ASSERT(x87_stack_depth_ > 0);
+
+ if (instr->NeedsCanonicalization()) {
+ __ fld(0);
+ __ fld(0);
+ __ FCmp();
+
+ __ j(parity_odd, &no_special_nan_handling);
+ __ sub(esp, Immediate(kDoubleSize));
+ __ fst_d(MemOperand(esp, 0));
+ __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
+ Immediate(kHoleNanUpper32));
+ __ add(esp, Immediate(kDoubleSize));
+ Label canonicalize;
+ __ j(not_equal, &canonicalize);
+ __ jmp(&no_special_nan_handling);
+ __ bind(&canonicalize);
+ __ fstp(0);
+ __ fld_d(Operand::StaticVariable(canonical_nan_reference));
+ }
+
+ __ bind(&no_special_nan_handling);
+ __ fst_d(double_store_operand);
+ }
+ }
}
@@ -4805,9 +4878,6 @@
XMMRegister input_reg = ToDoubleRegister(instr->value());
__ ucomisd(input_reg, input_reg);
} else {
- if (!IsX87TopOfStack(instr->value())) {
- __ fld_d(ToOperand(instr->value()));
- }
__ fld(0);
__ fld(0);
__ FCmp();
@@ -4829,6 +4899,9 @@
__ j(not_equal, &canonicalize);
__ add(esp, Immediate(kDoubleSize));
__ mov(reg, factory()->the_hole_value());
+ if (!use_sse2) {
+ __ fstp(0);
+ }
__ jmp(&done);
__ bind(&canonicalize);
__ add(esp, Immediate(kDoubleSize));
@@ -4858,10 +4931,7 @@
XMMRegister input_reg = ToDoubleRegister(instr->value());
__ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
} else {
- if (!IsX87TopOfStack(instr->value())) {
- __ fld_d(ToOperand(instr->value()));
- }
- __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
+ __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
}
__ bind(&done);
}
@@ -4909,6 +4979,79 @@
}
+void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
+ Register temp_reg,
+ bool deoptimize_on_undefined,
+ bool deoptimize_on_minus_zero,
+ LEnvironment* env,
+ NumberUntagDMode mode) {
+ Label load_smi, done;
+
+ if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
+ // Smi check.
+ __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
+
+ // Heap number map check.
+ __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+ factory()->heap_number_map());
+ if (deoptimize_on_undefined) {
+ DeoptimizeIf(not_equal, env);
+ } else {
+ Label heap_number;
+ __ j(equal, &heap_number, Label::kNear);
+
+ __ cmp(input_reg, factory()->undefined_value());
+ DeoptimizeIf(not_equal, env);
+
+ // Convert undefined to NaN.
+ ExternalReference nan =
+ ExternalReference::address_of_canonical_non_hole_nan();
+ __ fld_d(Operand::StaticVariable(nan));
+ __ jmp(&done, Label::kNear);
+ __ bind(&heap_number);
+ }
+ // Heap number to x87 conversion.
+ __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
+ if (deoptimize_on_minus_zero) {
+ __ fldz();
+ __ FCmp();
+ __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
+ __ j(not_zero, &done, Label::kNear);
+
+ // Use general purpose registers to check if we have -0.0
+ __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+ __ test(temp_reg, Immediate(HeapNumber::kSignMask));
+ __ j(zero, &done, Label::kNear);
+
+ // Pop FPU stack before deoptimizing.
+ __ fstp(0);
+ DeoptimizeIf(not_zero, env);
+ }
+ __ jmp(&done, Label::kNear);
+ } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
+ __ test(input_reg, Immediate(kSmiTagMask));
+ DeoptimizeIf(not_equal, env);
+ } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
+ __ test(input_reg, Immediate(kSmiTagMask));
+ __ j(zero, &load_smi);
+ ExternalReference hole_nan_reference =
+ ExternalReference::address_of_the_hole_nan();
+ __ fld_d(Operand::StaticVariable(hole_nan_reference));
+ __ jmp(&done, Label::kNear);
+ } else {
+ ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
+ }
+
+ __ bind(&load_smi);
+ __ SmiUntag(input_reg); // Untag smi before converting to float.
+ __ push(input_reg);
+ __ fild_s(Operand(esp, 0));
+ __ pop(input_reg);
+ __ SmiTag(input_reg); // Retag smi.
+ __ bind(&done);
+}
+
+
void LCodeGen::EmitNumberUntagD(Register input_reg,
Register temp_reg,
XMMRegister result_reg,
@@ -5021,7 +5164,7 @@
__ fisttp_d(Operand(esp, 0));
__ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
__ add(Operand(esp), Immediate(kDoubleSize));
- } else {
+ } else if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(masm(), SSE2);
XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
__ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
@@ -5035,6 +5178,8 @@
__ ucomisd(xmm_temp, xmm0);
DeoptimizeIf(not_equal, instr->environment());
DeoptimizeIf(parity_even, instr->environment()); // NaN.
+ } else {
+ UNREACHABLE();
}
} else if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(masm(), SSE2);
@@ -5079,18 +5224,169 @@
LOperand* input = instr->value();
ASSERT(input->IsRegister());
- ASSERT(input->Equals(instr->result()));
-
Register input_reg = ToRegister(input);
+ ASSERT(input_reg.is(ToRegister(instr->result())));
DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
+ __ JumpIfNotSmi(input_reg, deferred->entry());
+ __ SmiUntag(input_reg);
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
+ Label done, heap_number;
+ Register result_reg = ToRegister(instr->result());
+ Register input_reg = ToRegister(instr->value());
+
+ // Heap number map check.
+ __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+ factory()->heap_number_map());
+ __ j(equal, &heap_number, Label::kNear);
+ // Check for undefined. Undefined is converted to zero for truncating
+ // conversions.
+ __ cmp(input_reg, factory()->undefined_value());
+ __ RecordComment("Deferred TaggedToI: cannot truncate");
+ DeoptimizeIf(not_equal, instr->environment());
+ __ xor_(result_reg, result_reg);
+ __ jmp(&done, Label::kFar);
+ __ bind(&heap_number);
+
+ // Surprisingly, all of this crazy bit manipulation is considerably
+ // faster than using the built-in x86 CPU conversion functions (about 6x).
+ Label right_exponent, adjust_bias, zero_result;
+ Register scratch = ToRegister(instr->scratch());
+ Register scratch2 = ToRegister(instr->scratch2());
+ // Get exponent word.
+ __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+ // Get exponent alone in scratch2.
+ __ mov(scratch2, scratch);
+ __ and_(scratch2, HeapNumber::kExponentMask);
+ __ shr(scratch2, HeapNumber::kExponentShift);
+ if (instr->truncating()) {
+ __ j(zero, &zero_result);
+ } else {
+ __ j(not_zero, &adjust_bias);
+ __ test(scratch, Immediate(HeapNumber::kMantissaMask));
+ DeoptimizeIf(not_zero, instr->environment());
+ __ cmp(FieldOperand(input_reg, HeapNumber::kMantissaOffset), Immediate(0));
+ DeoptimizeIf(not_equal, instr->environment());
+ __ bind(&adjust_bias);
+ }
+ __ sub(scratch2, Immediate(HeapNumber::kExponentBias));
+ if (!instr->truncating()) {
+ DeoptimizeIf(negative, instr->environment());
+ } else {
+ __ j(negative, &zero_result);
+ }
+
+ // Get the second half of the double. For some exponents we don't
+ // actually need this because the bits get shifted out again, but
+ // it's probably slower to test than just to do it.
+ Register scratch3 = ToRegister(instr->scratch3());
+ __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
+ __ xor_(result_reg, result_reg);
+
+ const uint32_t non_int32_exponent = 31;
+ __ cmp(scratch2, Immediate(non_int32_exponent));
+ // If we have a match of the int32 exponent then skip some logic.
+ __ j(equal, &right_exponent, Label::kNear);
+ // If the number doesn't find in an int32, deopt.
+ DeoptimizeIf(greater, instr->environment());
+
+ // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
+ // < 31.
+ __ mov(result_reg, Immediate(31));
+ __ sub(result_reg, scratch2);
+
+ __ bind(&right_exponent);
+
+ // Save off exponent for negative check later.
+ __ mov(scratch2, scratch);
+
+ // Here result_reg is the shift, scratch is the exponent word.
+ // Get the top bits of the mantissa.
+ __ and_(scratch, HeapNumber::kMantissaMask);
+ // Put back the implicit 1.
+ __ or_(scratch, 1 << HeapNumber::kExponentShift);
+ // Shift up the mantissa bits to take up the space the exponent used to
+ // take. We have kExponentShift + 1 significant bits int he low end of the
+ // word. Shift them to the top bits.
+ const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
+ __ shl(scratch, shift_distance);
+ if (!instr->truncating()) {
+ // If not truncating, a non-zero value in the bottom 22 bits means a
+ // non-integral value --> trigger a deopt.
+ __ test(scratch3, Immediate((1 << (32 - shift_distance)) - 1));
+ DeoptimizeIf(not_equal, instr->environment());
+ }
+ // Shift down 22 bits to get the most significant 10 bits or the low
+ // mantissa word.
+ __ shr(scratch3, 32 - shift_distance);
+ __ or_(scratch3, scratch);
+ if (!instr->truncating()) {
+ // If truncating, a non-zero value in the bits that will be shifted away
+ // when adjusting the exponent means rounding --> deopt.
+ __ mov(scratch, 0x1);
+ ASSERT(result_reg.is(ecx));
+ __ shl_cl(scratch);
+ __ dec(scratch);
+ __ test(scratch3, scratch);
+ DeoptimizeIf(not_equal, instr->environment());
+ }
+ // Move down according to the exponent.
+ ASSERT(result_reg.is(ecx));
+ __ shr_cl(scratch3);
+ // Now the unsigned 32-bit answer is in scratch3. We need to move it to
+ // result_reg and we may need to fix the sign.
+ Label negative_result;
+ __ xor_(result_reg, result_reg);
+ __ cmp(scratch2, result_reg);
+ __ j(less, &negative_result, Label::kNear);
+ __ cmp(scratch3, result_reg);
+ __ mov(result_reg, scratch3);
+ // If the result is > MAX_INT, result doesn't fit in signed 32-bit --> deopt.
+ DeoptimizeIf(less, instr->environment());
+ __ jmp(&done, Label::kNear);
+ __ bind(&zero_result);
+ __ xor_(result_reg, result_reg);
+ __ jmp(&done, Label::kNear);
+ __ bind(&negative_result);
+ __ sub(result_reg, scratch3);
+ if (!instr->truncating()) {
+ // -0.0 triggers a deopt.
+ DeoptimizeIf(zero, instr->environment());
+ }
+ // If the negative subtraction overflows into a positive number, there was an
+ // overflow --> deopt.
+ DeoptimizeIf(positive, instr->environment());
+ __ bind(&done);
+}
+
+
+void LCodeGen::DoTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
+ class DeferredTaggedToINoSSE2: public LDeferredCode {
+ public:
+ DeferredTaggedToINoSSE2(LCodeGen* codegen, LTaggedToINoSSE2* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() { codegen()->DoDeferredTaggedToINoSSE2(instr_); }
+ virtual LInstruction* instr() { return instr_; }
+ private:
+ LTaggedToINoSSE2* instr_;
+ };
+
+ LOperand* input = instr->value();
+ ASSERT(input->IsRegister());
+ Register input_reg = ToRegister(input);
+ ASSERT(input_reg.is(ToRegister(instr->result())));
+
+ DeferredTaggedToINoSSE2* deferred =
+ new(zone()) DeferredTaggedToINoSSE2(this, instr);
+
// Smi check.
__ JumpIfNotSmi(input_reg, deferred->entry());
-
- // Smi to int32 conversion
__ SmiUntag(input_reg); // Untag smi.
-
__ bind(deferred->exit());
}
@@ -5103,32 +5399,31 @@
LOperand* result = instr->result();
ASSERT(result->IsDoubleRegister());
- if (CpuFeatures::IsSupported(SSE2)) {
- CpuFeatureScope scope(masm(), SSE2);
- Register input_reg = ToRegister(input);
- XMMRegister result_reg = ToDoubleRegister(result);
+ Register input_reg = ToRegister(input);
+ bool deoptimize_on_minus_zero =
+ instr->hydrogen()->deoptimize_on_minus_zero();
+ Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
- bool deoptimize_on_minus_zero =
- instr->hydrogen()->deoptimize_on_minus_zero();
- Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
-
- NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
- HValue* value = instr->hydrogen()->value();
- if (value->type().IsSmi()) {
- if (value->IsLoadKeyed()) {
- HLoadKeyed* load = HLoadKeyed::cast(value);
- if (load->UsesMustHandleHole()) {
- if (load->hole_mode() == ALLOW_RETURN_HOLE) {
- mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
- } else {
- mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
- }
+ NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
+ HValue* value = instr->hydrogen()->value();
+ if (value->type().IsSmi()) {
+ if (value->IsLoadKeyed()) {
+ HLoadKeyed* load = HLoadKeyed::cast(value);
+ if (load->UsesMustHandleHole()) {
+ if (load->hole_mode() == ALLOW_RETURN_HOLE) {
+ mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
} else {
- mode = NUMBER_CANDIDATE_IS_SMI;
+ mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
}
+ } else {
+ mode = NUMBER_CANDIDATE_IS_SMI;
}
}
+ }
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatureScope scope(masm(), SSE2);
+ XMMRegister result_reg = ToDoubleRegister(result);
EmitNumberUntagD(input_reg,
temp_reg,
result_reg,
@@ -5137,7 +5432,13 @@
instr->environment(),
mode);
} else {
- UNIMPLEMENTED();
+ EmitNumberUntagDNoSSE2(input_reg,
+ temp_reg,
+ instr->hydrogen()->deoptimize_on_undefined(),
+ deoptimize_on_minus_zero,
+ instr->environment(),
+ mode);
+ CurrentInstructionReturnsX87Result();
}
}
@@ -5409,13 +5710,133 @@
__ bind(&is_smi);
__ SmiUntag(input_reg);
__ ClampUint8(input_reg);
+ __ bind(&done);
+}
+
+void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
+ Register input_reg = ToRegister(instr->unclamped());
+ Register result_reg = ToRegister(instr->result());
+ Register scratch = ToRegister(instr->scratch());
+ Register scratch2 = ToRegister(instr->scratch2());
+ Register scratch3 = ToRegister(instr->scratch3());
+ Label is_smi, done, heap_number, valid_exponent,
+ largest_value, zero_result, maybe_nan_or_infinity;
+
+ __ JumpIfSmi(input_reg, &is_smi);
+
+ // Check for heap number
+ __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+ factory()->heap_number_map());
+ __ j(equal, &heap_number, Label::kFar);
+
+ // Check for undefined. Undefined is converted to zero for clamping
+ // conversions.
+ __ cmp(input_reg, factory()->undefined_value());
+ DeoptimizeIf(not_equal, instr->environment());
+ __ jmp(&zero_result);
+
+ // Heap number
+ __ bind(&heap_number);
+
+ // Surprisingly, all of the hand-crafted bit-manipulations below are much
+ // faster than the x86 FPU built-in instruction, especially since "banker's
+ // rounding" would be additionally very expensive
+
+ // Get exponent word.
+ __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+ __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
+
+ // Test for negative values --> clamp to zero
+ __ test(scratch, scratch);
+ __ j(negative, &zero_result);
+
+ // Get exponent alone in scratch2.
+ __ mov(scratch2, scratch);
+ __ and_(scratch2, HeapNumber::kExponentMask);
+ __ shr(scratch2, HeapNumber::kExponentShift);
+ __ j(zero, &zero_result);
+ __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1));
+ __ j(negative, &zero_result);
+
+ const uint32_t non_int8_exponent = 7;
+ __ cmp(scratch2, Immediate(non_int8_exponent + 1));
+ // If the exponent is too big, check for special values.
+ __ j(greater, &maybe_nan_or_infinity, Label::kNear);
+
+ __ bind(&valid_exponent);
+ // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
+ // < 7. The shift bias is the number of bits to shift the mantissa such that
+ // with an exponent of 7 such the that top-most one is in bit 30, allowing
+ // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to
+ // 1).
+ int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1;
+ __ lea(result_reg, MemOperand(scratch2, shift_bias));
+ // Here result_reg (ecx) is the shift, scratch is the exponent word. Get the
+ // top bits of the mantissa.
+ __ and_(scratch, HeapNumber::kMantissaMask);
+ // Put back the implicit 1 of the mantissa
+ __ or_(scratch, 1 << HeapNumber::kExponentShift);
+ // Shift up to round
+ __ shl_cl(scratch);
+ // Use "banker's rounding" to spec: If fractional part of number is 0.5, then
+ // use the bit in the "ones" place and add it to the "halves" place, which has
+ // the effect of rounding to even.
+ __ mov(scratch2, scratch);
+ const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8;
+ const uint32_t one_bit_shift = one_half_bit_shift + 1;
+ __ and_(scratch2, Immediate((1 << one_bit_shift) - 1));
+ __ cmp(scratch2, Immediate(1 << one_half_bit_shift));
+ Label no_round;
+ __ j(less, &no_round);
+ Label round_up;
+ __ mov(scratch2, Immediate(1 << one_half_bit_shift));
+ __ j(greater, &round_up);
+ __ test(scratch3, scratch3);
+ __ j(not_zero, &round_up);
+ __ mov(scratch2, scratch);
+ __ and_(scratch2, Immediate(1 << one_bit_shift));
+ __ shr(scratch2, 1);
+ __ bind(&round_up);
+ __ add(scratch, scratch2);
+ __ j(overflow, &largest_value);
+ __ bind(&no_round);
+ __ shr(scratch, 23);
+ __ mov(result_reg, scratch);
+ __ jmp(&done, Label::kNear);
+
+ __ bind(&maybe_nan_or_infinity);
+ // Check for NaN/Infinity, all other values map to 255
+ __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1));
+ __ j(not_equal, &largest_value, Label::kNear);
+
+ // Check for NaN, which differs from Infinity in that at least one mantissa
+ // bit is set.
+ __ and_(scratch, HeapNumber::kMantissaMask);
+ __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
+ __ j(not_zero, &zero_result); // M!=0 --> NaN
+ // Infinity -> Fall through to map to 255.
+
+ __ bind(&largest_value);
+ __ mov(result_reg, Immediate(255));
+ __ jmp(&done, Label::kNear);
+
+ __ bind(&zero_result);
+ __ xor_(result_reg, result_reg);
+ __ jmp(&done);
+
+ // smi
+ __ bind(&is_smi);
+ if (!input_reg.is(result_reg)) {
+ __ mov(result_reg, input_reg);
+ }
+ __ SmiUntag(result_reg);
+ __ ClampUint8(result_reg);
__ bind(&done);
}
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
- ASSERT(instr->temp()->Equals(instr->result()));
Register reg = ToRegister(instr->temp());
ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
@@ -5423,15 +5844,10 @@
ASSERT(prototypes->length() == maps->length());
- // TODO(ulan): Move this check to hydrogen and split HCheckPrototypeMaps
- // into two instruction: one that checks the prototypes and another that
- // loads the holder (HConstant). Find a way to do it without breaking
- // parallel recompilation.
if (instr->hydrogen()->CanOmitPrototypeChecks()) {
for (int i = 0; i < maps->length(); i++) {
prototype_maps_.Add(maps->at(i), info()->zone());
}
- __ LoadHeapObject(reg, prototypes->at(prototypes->length() - 1));
} else {
for (int i = 0; i < prototypes->length(); i++) {
__ LoadHeapObject(reg, prototypes->at(i));
@@ -5557,11 +5973,11 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+ }
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- }
__ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
@@ -5585,8 +6001,13 @@
__ StoreToSafepointRegisterSlot(result, size);
}
__ push(size);
- CallRuntimeFromDeferred(
- Runtime::kAllocateInNewSpace, 1, instr, instr->context());
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context());
+ } else {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInNewSpace, 1, instr, instr->context());
+ }
__ StoreToSafepointRegisterSlot(result, eax);
}
@@ -5615,26 +6036,33 @@
DeoptimizeIf(not_equal, instr->environment());
}
- // Set up the parameters to the stub/runtime call.
- __ PushHeapObject(literals);
- __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
- // Boilerplate already exists, constant elements are never accessed.
- // Pass an empty fixed array.
- __ push(Immediate(isolate()->factory()->empty_fixed_array()));
-
- // Pick the right runtime function or stub to call.
+ // Set up the parameters to the stub/runtime call and pick the right
+ // runtime function or stub to call. Boilerplate already exists,
+ // constant elements are never accessed, pass an empty fixed array.
int length = instr->hydrogen()->length();
if (instr->hydrogen()->IsCopyOnWrite()) {
ASSERT(instr->hydrogen()->depth() == 1);
+ __ LoadHeapObject(eax, literals);
+ __ mov(ebx, Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ mov(ecx, Immediate(isolate()->factory()->empty_fixed_array()));
FastCloneShallowArrayStub::Mode mode =
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else if (instr->hydrogen()->depth() > 1) {
+ __ PushHeapObject(literals);
+ __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ push(Immediate(isolate()->factory()->empty_fixed_array()));
CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ PushHeapObject(literals);
+ __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ push(Immediate(isolate()->factory()->empty_fixed_array()));
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
} else {
+ __ LoadHeapObject(eax, literals);
+ __ mov(ebx, Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ mov(ecx, Immediate(isolate()->factory()->empty_fixed_array()));
FastCloneShallowArrayStub::Mode mode =
boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
@@ -5645,178 +6073,6 @@
}
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
- Register result,
- Register source,
- int* offset,
- AllocationSiteMode mode) {
- ASSERT(!source.is(ecx));
- ASSERT(!result.is(ecx));
-
- bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
- object->map()->CanTrackAllocationSite();
-
- if (FLAG_debug_code) {
- __ LoadHeapObject(ecx, object);
- __ cmp(source, ecx);
- __ Assert(equal, "Unexpected object literal boilerplate");
- __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
- __ cmp(ecx, Handle<Map>(object->map()));
- __ Assert(equal, "Unexpected boilerplate map");
- __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
- __ and_(ecx, Map::kElementsKindMask);
- __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
- __ Assert(equal, "Unexpected boilerplate elements kind");
- }
-
- // Only elements backing stores for non-COW arrays need to be copied.
- Handle<FixedArrayBase> elements(object->elements());
- bool has_elements = elements->length() > 0 &&
- elements->map() != isolate()->heap()->fixed_cow_array_map();
-
- // Increase the offset so that subsequent objects end up right after
- // this object and its backing store.
- int object_offset = *offset;
- int object_size = object->map()->instance_size();
- int elements_size = has_elements ? elements->Size() : 0;
- int elements_offset = *offset + object_size;
- if (create_allocation_site_info) {
- elements_offset += AllocationSiteInfo::kSize;
- *offset += AllocationSiteInfo::kSize;
- }
-
- *offset += object_size + elements_size;
-
- // Copy object header.
- ASSERT(object->properties()->length() == 0);
- int inobject_properties = object->map()->inobject_properties();
- int header_size = object_size - inobject_properties * kPointerSize;
- for (int i = 0; i < header_size; i += kPointerSize) {
- if (has_elements && i == JSObject::kElementsOffset) {
- __ lea(ecx, Operand(result, elements_offset));
- } else {
- __ mov(ecx, FieldOperand(source, i));
- }
- __ mov(FieldOperand(result, object_offset + i), ecx);
- }
-
- // Copy in-object properties.
- for (int i = 0; i < inobject_properties; i++) {
- int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
- Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
- isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ lea(ecx, Operand(result, *offset));
- __ mov(FieldOperand(result, total_offset), ecx);
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
- __ mov(FieldOperand(result, total_offset), ecx);
- } else {
- __ mov(FieldOperand(result, total_offset), Immediate(value));
- }
- }
-
- // Build Allocation Site Info if desired
- if (create_allocation_site_info) {
- __ mov(FieldOperand(result, object_size),
- Immediate(Handle<Map>(isolate()->heap()->
- allocation_site_info_map())));
- __ mov(FieldOperand(result, object_size + kPointerSize), source);
- }
-
- if (has_elements) {
- // Copy elements backing store header.
- __ LoadHeapObject(source, elements);
- for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
- __ mov(ecx, FieldOperand(source, i));
- __ mov(FieldOperand(result, elements_offset + i), ecx);
- }
-
- // Copy elements backing store content.
- int elements_length = elements->length();
- if (elements->IsFixedDoubleArray()) {
- Handle<FixedDoubleArray> double_array =
- Handle<FixedDoubleArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int64_t value = double_array->get_representation(i);
- int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
- int32_t value_high = static_cast<int32_t>(value >> 32);
- int total_offset =
- elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
- __ mov(FieldOperand(result, total_offset), Immediate(value_low));
- __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
- }
- } else if (elements->IsFixedArray()) {
- Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value(fast_elements->get(i), isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ lea(ecx, Operand(result, *offset));
- __ mov(FieldOperand(result, total_offset), ecx);
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
- __ mov(FieldOperand(result, total_offset), ecx);
- } else {
- __ mov(FieldOperand(result, total_offset), Immediate(value));
- }
- }
- } else {
- UNREACHABLE();
- }
- }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
- ASSERT(ToRegister(instr->context()).is(esi));
- int size = instr->hydrogen()->total_size();
- ElementsKind boilerplate_elements_kind =
- instr->hydrogen()->boilerplate()->GetElementsKind();
-
- // Deopt if the literal boilerplate ElementsKind is of a type different than
- // the expected one. The check isn't necessary if the boilerplate has already
- // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
- if (CanTransitionToMoreGeneralFastElementsKind(
- boilerplate_elements_kind, true)) {
- __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
- __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
- // Load the map's "bit field 2". We only need the first byte,
- // but the following masking takes care of that anyway.
- __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
- // Retrieve elements_kind from bit field 2.
- __ and_(ecx, Map::kElementsKindMask);
- __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
- DeoptimizeIf(not_equal, instr->environment());
- }
-
- // Allocate all objects that are part of the literal in one big
- // allocation. This avoids multiple limit checks.
- Label allocated, runtime_allocate;
- __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
- __ jmp(&allocated);
-
- __ bind(&runtime_allocate);
- __ push(Immediate(Smi::FromInt(size)));
- CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
- __ bind(&allocated);
- int offset = 0;
- __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
- EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset,
- instr->hydrogen()->allocation_site_mode());
- ASSERT_EQ(size, offset);
-}
-
-
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
Handle<FixedArray> literals(instr->environment()->closure()->literals());
@@ -5923,7 +6179,8 @@
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode());
+ FastNewClosureStub stub(shared_info->language_mode(),
+ shared_info->is_generator());
__ push(Immediate(shared_info));
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else {
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 3a38e32..362f091 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -68,6 +68,7 @@
osr_pc_offset_(-1),
last_lazy_deopt_pc_(0),
frame_is_built_(false),
+ x87_stack_depth_(0),
safepoints_(info->zone()),
resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) {
@@ -102,10 +103,17 @@
return Immediate(ToInteger32(LConstantOperand::cast(op)));
}
- Handle<Object> ToHandle(LConstantOperand* op) const;
+ // Support for non-sse2 (x87) floating point stack handling.
+ // These functions maintain the depth of the stack (either 0 or 1)
+ void PushX87DoubleOperand(Operand src);
+ void PushX87FloatOperand(Operand src);
+ void ReadX87Operand(Operand dst);
+ bool X87StackNonEmpty() const { return x87_stack_depth_ > 0; }
+ void PopX87();
+ void CurrentInstructionReturnsX87Result();
+ void FlushX87StackIfNecessary(LInstruction* instr);
- // A utility for instructions that return floating point values on X87.
- void HandleX87FPReturnValue(LInstruction* instr);
+ Handle<Object> ToHandle(LConstantOperand* op) const;
// The operand denoting the second word (the one with a higher address) of
// a double stack slot.
@@ -129,7 +137,8 @@
IntegerSignedness signedness);
void DoDeferredTaggedToI(LTaggedToI* instr);
- void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+ void DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr);
+ void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -281,15 +290,7 @@
uint32_t offset,
uint32_t additional_index = 0);
- // Specific math operations - used from DoUnaryMathOperation.
- void EmitIntegerMathAbs(LUnaryMathOperation* instr);
- void DoMathAbs(LUnaryMathOperation* instr);
- void DoMathFloor(LUnaryMathOperation* instr);
- void DoMathSqrt(LUnaryMathOperation* instr);
- void DoMathLog(LUnaryMathOperation* instr);
- void DoMathTan(LUnaryMathOperation* instr);
- void DoMathCos(LUnaryMathOperation* instr);
- void DoMathSin(LUnaryMathOperation* instr);
+ void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers,
@@ -315,6 +316,14 @@
LEnvironment* env,
NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
+ void EmitNumberUntagDNoSSE2(
+ Register input,
+ Register temp,
+ bool deoptimize_on_undefined,
+ bool deoptimize_on_minus_zero,
+ LEnvironment* env,
+ NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
+
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
@@ -404,6 +413,7 @@
int osr_pc_offset_;
int last_lazy_deopt_pc_;
bool frame_is_built_;
+ int x87_stack_depth_;
// Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code.
diff --git a/src/ia32/lithium-gap-resolver-ia32.cc b/src/ia32/lithium-gap-resolver-ia32.cc
index b062ba5..6c7e375 100644
--- a/src/ia32/lithium-gap-resolver-ia32.cc
+++ b/src/ia32/lithium-gap-resolver-ia32.cc
@@ -324,29 +324,61 @@
}
} else if (source->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), SSE2);
- XMMRegister src = cgen_->ToDoubleRegister(source);
- if (destination->IsDoubleRegister()) {
- XMMRegister dst = cgen_->ToDoubleRegister(destination);
- __ movaps(dst, src);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatureScope scope(cgen_->masm(), SSE2);
+ XMMRegister src = cgen_->ToDoubleRegister(source);
+ if (destination->IsDoubleRegister()) {
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ __ movaps(dst, src);
+ } else {
+ ASSERT(destination->IsDoubleStackSlot());
+ Operand dst = cgen_->ToOperand(destination);
+ __ movdbl(dst, src);
+ }
} else {
+ // load from the register onto the stack, store in destination, which must
+ // be a double stack slot in the non-SSE2 case.
+ ASSERT(source->index() == 0); // source is on top of the stack
ASSERT(destination->IsDoubleStackSlot());
Operand dst = cgen_->ToOperand(destination);
- __ movdbl(dst, src);
+ cgen_->ReadX87Operand(dst);
}
} else if (source->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), SSE2);
- ASSERT(destination->IsDoubleRegister() ||
- destination->IsDoubleStackSlot());
- Operand src = cgen_->ToOperand(source);
- if (destination->IsDoubleRegister()) {
- XMMRegister dst = cgen_->ToDoubleRegister(destination);
- __ movdbl(dst, src);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatureScope scope(cgen_->masm(), SSE2);
+ ASSERT(destination->IsDoubleRegister() ||
+ destination->IsDoubleStackSlot());
+ Operand src = cgen_->ToOperand(source);
+ if (destination->IsDoubleRegister()) {
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ __ movdbl(dst, src);
+ } else {
+ // We rely on having xmm0 available as a fixed scratch register.
+ Operand dst = cgen_->ToOperand(destination);
+ __ movdbl(xmm0, src);
+ __ movdbl(dst, xmm0);
+ }
} else {
- // We rely on having xmm0 available as a fixed scratch register.
- Operand dst = cgen_->ToOperand(destination);
- __ movdbl(xmm0, src);
- __ movdbl(dst, xmm0);
+ // load from the stack slot on top of the floating point stack, and then
+ // store in destination. If destination is a double register, then it
+ // represents the top of the stack and nothing needs to be done.
+ if (destination->IsDoubleStackSlot()) {
+ Register tmp = EnsureTempRegister();
+ Operand src0 = cgen_->ToOperand(source);
+ Operand src1 = cgen_->HighOperand(source);
+ Operand dst0 = cgen_->ToOperand(destination);
+ Operand dst1 = cgen_->HighOperand(destination);
+ __ mov(tmp, src0); // Then use tmp to copy source to destination.
+ __ mov(dst0, tmp);
+ __ mov(tmp, src1);
+ __ mov(dst1, tmp);
+ } else {
+ Operand src = cgen_->ToOperand(source);
+ if (cgen_->X87StackNonEmpty()) {
+ cgen_->PopX87();
+ }
+ cgen_->PushX87DoubleOperand(src);
+ }
}
} else {
UNREACHABLE();
@@ -419,21 +451,19 @@
__ movaps(xmm0, src);
__ movaps(src, dst);
__ movaps(dst, xmm0);
-
} else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) {
CpuFeatureScope scope(cgen_->masm(), SSE2);
// XMM register-memory swap. We rely on having xmm0
// available as a fixed scratch register.
ASSERT(source->IsDoubleStackSlot() || destination->IsDoubleStackSlot());
XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister()
- ? source
- : destination);
+ ? source
+ : destination);
Operand other =
cgen_->ToOperand(source->IsDoubleRegister() ? destination : source);
__ movdbl(xmm0, other);
__ movdbl(other, reg);
__ movdbl(reg, Operand(xmm0));
-
} else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
CpuFeatureScope scope(cgen_->masm(), SSE2);
// Double-width memory-to-memory. Spill on demand to use a general
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 102515a..a7bb2d9 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -91,6 +91,22 @@
#endif
+bool LInstruction::HasDoubleRegisterResult() {
+ return HasResult() && result()->IsDoubleRegister();
+}
+
+
+bool LInstruction::HasDoubleRegisterInput() {
+ for (int i = 0; i < InputCount(); i++) {
+ LOperand* op = InputAt(i);
+ if (op->IsDoubleRegister()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic());
@@ -304,29 +320,6 @@
}
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
- stream->Add("/%s ", hydrogen()->OpName());
- value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
- value()->PrintTo(stream);
-}
-
-
-void LMathPowHalf::PrintDataTo(StringStream* stream) {
- stream->Add("/pow_half ");
- value()->PrintTo(stream);
-}
-
-
-void LMathRound::PrintDataTo(StringStream* stream) {
- stream->Add("/round ");
- value()->PrintTo(stream);
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -542,6 +535,11 @@
}
+LOperand* LChunkBuilder::UseX87TopOfStack(HValue* value) {
+ return Use(value, ToUnallocated(x87tos));
+}
+
+
LOperand* LChunkBuilder::UseRegister(HValue* value) {
return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
@@ -1187,62 +1185,105 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
- BuiltinFunctionId op = instr->op();
- if (op == kMathLog) {
- ASSERT(instr->representation().IsDouble());
- ASSERT(instr->value()->representation().IsDouble());
- LOperand* context = UseAny(instr->context()); // Not actually used.
- LOperand* input = UseRegisterAtStart(instr->value());
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
- input);
- return DefineSameAsFirst(result);
- } else if (op == kMathExp) {
- ASSERT(instr->representation().IsDouble());
- ASSERT(instr->value()->representation().IsDouble());
- LOperand* value = UseTempRegister(instr->value());
- LOperand* temp1 = TempRegister();
- LOperand* temp2 = TempRegister();
- LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
- return DefineAsRegister(result);
- } else if (op == kMathSin || op == kMathCos || op == kMathTan) {
- LOperand* context = UseFixed(instr->context(), esi);
- LOperand* input = UseFixedDouble(instr->value(), xmm1);
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
- input);
- return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
- } else {
- LOperand* context = UseAny(instr->context()); // Deferred use by MathAbs.
- LOperand* input = NULL;
- if (op == kMathPowHalf) {
- input = UseRegisterAtStart(instr->value());
- LOperand* temp = TempRegister();
- LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
- return DefineSameAsFirst(result);
- } else if (op == kMathRound) {
- input = UseRegister(instr->value());
- LOperand* temp = FixedTemp(xmm4);
- LMathRound* result = new(zone()) LMathRound(context, input, temp);
- return AssignEnvironment(DefineAsRegister(result));
- } else {
- input = UseRegisterAtStart(instr->value());
- }
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
- input);
- switch (op) {
- case kMathAbs:
- return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
- case kMathFloor:
- return AssignEnvironment(DefineAsRegister(result));
- case kMathSqrt:
- return DefineSameAsFirst(result);
- default:
- UNREACHABLE();
- return NULL;
- }
+ switch (instr->op()) {
+ case kMathFloor: return DoMathFloor(instr);
+ case kMathRound: return DoMathRound(instr);
+ case kMathAbs: return DoMathAbs(instr);
+ case kMathLog: return DoMathLog(instr);
+ case kMathSin: return DoMathSin(instr);
+ case kMathCos: return DoMathCos(instr);
+ case kMathTan: return DoMathTan(instr);
+ case kMathExp: return DoMathExp(instr);
+ case kMathSqrt: return DoMathSqrt(instr);
+ case kMathPowHalf: return DoMathPowHalf(instr);
+ default:
+ UNREACHABLE();
+ return NULL;
}
}
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathFloor* result = new(zone()) LMathFloor(input);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+ LOperand* context = UseAny(instr->context());
+ LOperand* input = UseRegister(instr->value());
+ LOperand* temp = FixedTemp(xmm4);
+ LMathRound* result = new(zone()) LMathRound(context, input, temp);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+ LOperand* context = UseAny(instr->context()); // Deferred use.
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathAbs* result = new(zone()) LMathAbs(context, input);
+ return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathLog* result = new(zone()) LMathLog(input);
+ return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathSin* result = new(zone()) LMathSin(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathCos* result = new(zone()) LMathCos(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathTan* result = new(zone()) LMathTan(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* value = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
+ return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathSqrt* result = new(zone()) LMathSqrt(input);
+ return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+ LOperand* context = UseAny(instr->context());
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LOperand* temp = TempRegister();
+ LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
+ return DefineSameAsFirst(result);
+}
+
+
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), esi);
@@ -1861,20 +1902,33 @@
? TempRegister()
: NULL;
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
- return AssignEnvironment(DefineAsRegister(res));
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ return AssignEnvironment(DefineAsRegister(res));
+ } else {
+ return AssignEnvironment(DefineX87TOS(res));
+ }
} else {
ASSERT(to.IsInteger32());
- LOperand* value = UseRegister(instr->value());
if (instr->value()->type().IsSmi()) {
+ LOperand* value = UseRegister(instr->value());
return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
} else {
bool truncating = instr->CanTruncateToInt32();
- LOperand* xmm_temp =
- (truncating && CpuFeatures::IsSupported(SSE3))
- ? NULL
- : FixedTemp(xmm1);
- LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
- return AssignEnvironment(DefineSameAsFirst(res));
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ LOperand* value = UseRegister(instr->value());
+ LOperand* xmm_temp =
+ (truncating && CpuFeatures::IsSupported(SSE3))
+ ? NULL
+ : FixedTemp(xmm1);
+ LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
+ return AssignEnvironment(DefineSameAsFirst(res));
+ } else {
+ LOperand* value = UseFixed(instr->value(), ecx);
+ LTaggedToINoSSE2* res =
+ new(zone()) LTaggedToINoSSE2(value, TempRegister(),
+ TempRegister(), TempRegister());
+ return AssignEnvironment(DefineFixed(res, ecx));
+ }
}
}
} else if (from.IsDouble()) {
@@ -1947,7 +2001,7 @@
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
LUnallocated* temp = TempRegister();
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
- return AssignEnvironment(Define(result, temp));
+ return AssignEnvironment(result);
}
@@ -1992,12 +2046,20 @@
return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
} else {
ASSERT(input_rep.IsTagged());
- LOperand* reg = UseFixed(value, eax);
- // Register allocator doesn't (yet) support allocation of double
- // temps. Reserve xmm1 explicitly.
- LOperand* temp = FixedTemp(xmm1);
- LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
- return AssignEnvironment(DefineFixed(result, eax));
+ if (CpuFeatures::IsSupported(SSE2)) {
+ LOperand* reg = UseFixed(value, eax);
+ // Register allocator doesn't (yet) support allocation of double
+ // temps. Reserve xmm1 explicitly.
+ LOperand* temp = FixedTemp(xmm1);
+ LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
+ return AssignEnvironment(DefineFixed(result, eax));
+ } else {
+ LOperand* value = UseRegister(instr->value());
+ LClampTToUint8NoSSE2* res =
+ new(zone()) LClampTToUint8NoSSE2(value, TempRegister(),
+ TempRegister(), TempRegister());
+ return AssignEnvironment(DefineFixed(res, ecx));
+ }
}
}
@@ -2018,10 +2080,13 @@
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
double value = instr->DoubleValue();
- LOperand* temp = (BitCast<uint64_t, double>(value) != 0)
- ? TempRegister()
- : NULL;
- return DefineAsRegister(new(zone()) LConstantD(temp));
+ bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ LOperand* temp = value_is_zero ? NULL : TempRegister();
+ return DefineAsRegister(new(zone()) LConstantD(temp));
+ } else {
+ return DefineX87TOS(new(zone()) LConstantD(NULL));
+ }
} else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
@@ -2190,6 +2255,27 @@
}
+LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) {
+ ElementsKind elements_kind = instr->elements_kind();
+
+ // Determine if we need a byte register in this case for the value.
+ bool val_is_fixed_register =
+ elements_kind == EXTERNAL_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS;
+ if (val_is_fixed_register) {
+ return UseFixed(instr->value(), eax);
+ }
+
+ if (!CpuFeatures::IsSafeForSnapshot(SSE2) &&
+ IsDoubleOrFloatElementsKind(elements_kind)) {
+ return UseRegisterAtStart(instr->value());
+ }
+
+ return UseRegister(instr->value());
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
if (!instr->is_external()) {
ASSERT(instr->elements()->representation().IsTagged());
@@ -2198,7 +2284,12 @@
if (instr->value()->representation().IsDouble()) {
LOperand* object = UseRegisterAtStart(instr->elements());
- LOperand* val = UseTempRegister(instr->value());
+ LOperand* val = NULL;
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ val = UseRegisterAtStart(instr->value());
+ } else if (!instr->IsConstantHoleStore()) {
+ val = UseX87TopOfStack(instr->value());
+ }
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyed(object, key, val);
@@ -2228,15 +2319,7 @@
ASSERT(instr->elements()->representation().IsExternal());
LOperand* external_pointer = UseRegister(instr->elements());
- // Determine if we need a byte register in this case for the value.
- bool val_is_fixed_register =
- elements_kind == EXTERNAL_BYTE_ELEMENTS ||
- elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
- elements_kind == EXTERNAL_PIXEL_ELEMENTS;
-
- LOperand* val = val_is_fixed_register
- ? UseFixed(instr->value(), eax)
- : UseRegister(instr->value());
+ LOperand* val = GetStoreKeyedValueOperand(instr);
bool clobbers_key = ExternalArrayOpRequiresTemp(
instr->key()->representation(), elements_kind);
LOperand* key = clobbers_key
@@ -2400,13 +2483,6 @@
}
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
- LOperand* context = UseFixed(instr->context(), esi);
- return MarkAsCall(
- DefineFixed(new(zone()) LFastLiteral(context), eax), instr);
-}
-
-
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
LOperand* context = UseFixed(instr->context(), esi);
return MarkAsCall(
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 1c490bb..10272fd 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -74,6 +74,7 @@
V(ClampDToUint8) \
V(ClampIToUint8) \
V(ClampTToUint8) \
+ V(ClampTToUint8NoSSE2) \
V(ClassOfTestAndBranch) \
V(CmpIDAndBranch) \
V(CmpObjectEqAndBranch) \
@@ -91,7 +92,6 @@
V(DoubleToI) \
V(DummyUse) \
V(ElementsKind) \
- V(FastLiteral) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
@@ -128,11 +128,18 @@
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
+ V(MathAbs) \
+ V(MathCos) \
V(MathExp) \
+ V(MathFloor) \
V(MathFloorOfDiv) \
+ V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
+ V(MathSin) \
+ V(MathSqrt) \
+ V(MathTan) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -167,6 +174,7 @@
V(StringLength) \
V(SubI) \
V(TaggedToI) \
+ V(TaggedToINoSSE2) \
V(ThisFunction) \
V(Throw) \
V(ToFastProperties) \
@@ -174,7 +182,6 @@
V(TrapAllocationMemento) \
V(Typeof) \
V(TypeofIsAndBranch) \
- V(UnaryMathOperation) \
V(UnknownOSRValue) \
V(ValueOf) \
V(ForInPrepareMap) \
@@ -265,6 +272,9 @@
virtual bool HasResult() const = 0;
virtual LOperand* result() = 0;
+ bool HasDoubleRegisterResult();
+ bool HasDoubleRegisterInput();
+
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
@@ -645,9 +655,39 @@
};
-class LUnaryMathOperation: public LTemplateInstruction<1, 2, 0> {
+class LMathFloor: public LTemplateInstruction<1, 1, 0> {
public:
- LUnaryMathOperation(LOperand* context, LOperand* value) {
+ explicit LMathFloor(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathRound: public LTemplateInstruction<1, 2, 1> {
+ public:
+ LMathRound(LOperand* context, LOperand* value, LOperand* temp) {
+ inputs_[1] = context;
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* context() { return inputs_[1]; }
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LMathAbs(LOperand* context, LOperand* value) {
inputs_[1] = context;
inputs_[0] = value;
}
@@ -655,11 +695,56 @@
LOperand* context() { return inputs_[1]; }
LOperand* value() { return inputs_[0]; }
- DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+ DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
- virtual void PrintDataTo(StringStream* stream);
- BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathLog(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSin(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathCos(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathTan(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
};
@@ -679,8 +764,18 @@
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
- virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSqrt(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
};
@@ -697,27 +792,6 @@
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
-class LMathRound: public LTemplateInstruction<1, 2, 1> {
- public:
- LMathRound(LOperand* context, LOperand* value, LOperand* temp) {
- inputs_[1] = context;
- inputs_[0] = value;
- temps_[0] = temp;
- }
-
- LOperand* context() { return inputs_[1]; }
- LOperand* value() { return inputs_[0]; }
- LOperand* temp() { return temps_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
- DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
-
- virtual void PrintDataTo(StringStream* stream);
};
@@ -1088,6 +1162,10 @@
temps_[0] = temp;
}
+ virtual bool ClobbersDoubleRegisters() const {
+ return false;
+ }
+
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
@@ -1296,7 +1374,7 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+ DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
};
@@ -2018,6 +2096,31 @@
};
+// Truncating conversion from a tagged value to an int32.
+class LTaggedToINoSSE2: public LTemplateInstruction<1, 1, 3> {
+ public:
+ LTaggedToINoSSE2(LOperand* value,
+ LOperand* temp1,
+ LOperand* temp2,
+ LOperand* temp3) {
+ inputs_[0] = value;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ temps_[2] = temp3;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* scratch() { return temps_[0]; }
+ LOperand* scratch2() { return temps_[1]; }
+ LOperand* scratch3() { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(TaggedToINoSSE2, "tagged-to-i-nosse2")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+ bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
class LSmiTag: public LTemplateInstruction<1, 1, 0> {
public:
explicit LSmiTag(LOperand* value) {
@@ -2040,6 +2143,10 @@
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
+ virtual bool ClobbersDoubleRegisters() const {
+ return false;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change);
};
@@ -2313,7 +2420,7 @@
};
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
public:
explicit LCheckPrototypeMaps(LOperand* temp) {
temps_[0] = temp;
@@ -2380,6 +2487,30 @@
};
+// Truncating conversion from a tagged value to an int32.
+class LClampTToUint8NoSSE2: public LTemplateInstruction<1, 1, 3> {
+ public:
+ LClampTToUint8NoSSE2(LOperand* unclamped,
+ LOperand* temp1,
+ LOperand* temp2,
+ LOperand* temp3) {
+ inputs_[0] = unclamped;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ temps_[2] = temp3;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+ LOperand* scratch() { return temps_[0]; }
+ LOperand* scratch2() { return temps_[1]; }
+ LOperand* scratch3() { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8NoSSE2,
+ "clamp-t-to-uint8-nosse2")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+};
+
+
class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckNonSmi(LOperand* value) {
@@ -2424,19 +2555,6 @@
};
-class LFastLiteral: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LFastLiteral(LOperand* context) {
- inputs_[0] = context;
- }
-
- LOperand* context() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
- DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
class LArrayLiteral: public LTemplateInstruction<1, 1, 0> {
public:
explicit LArrayLiteral(LOperand* context) {
@@ -2712,6 +2830,17 @@
static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
+ LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+ LInstruction* DoMathRound(HUnaryMathOperation* instr);
+ LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+ LInstruction* DoMathLog(HUnaryMathOperation* instr);
+ LInstruction* DoMathSin(HUnaryMathOperation* instr);
+ LInstruction* DoMathCos(HUnaryMathOperation* instr);
+ LInstruction* DoMathTan(HUnaryMathOperation* instr);
+ LInstruction* DoMathExp(HUnaryMathOperation* instr);
+ LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+ LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
private:
enum Status {
UNUSED,
@@ -2742,6 +2871,7 @@
MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
XMMRegister fixed_register);
+ MUST_USE_RESULT LOperand* UseX87TopOfStack(HValue* value);
// A value that is guaranteed to be allocated to a register.
// Operand created by UseRegister is guaranteed to be live until the end of
@@ -2827,6 +2957,8 @@
LInstruction* DoArithmeticT(Token::Value op,
HArithmeticBinaryOperation* instr);
+ LOperand* GetStoreKeyedValueOperand(HStoreKeyed* instr);
+
LPlatformChunk* chunk_;
CompilationInfo* info_;
HGraph* const graph_;
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 3d3dabc..3228e83 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -1024,69 +1024,65 @@
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
- Register scratch,
+ Register scratch1,
+ Register scratch2,
Label* miss) {
Label same_contexts;
- ASSERT(!holder_reg.is(scratch));
+ ASSERT(!holder_reg.is(scratch1));
+ ASSERT(!holder_reg.is(scratch2));
+ ASSERT(!scratch1.is(scratch2));
// Load current lexical context from the stack frame.
- mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
+ mov(scratch1, Operand(ebp, StandardFrameConstants::kContextOffset));
// When generating debug code, make sure the lexical context is set.
if (emit_debug_code()) {
- cmp(scratch, Immediate(0));
+ cmp(scratch1, Immediate(0));
Check(not_equal, "we should not have an empty lexical context");
}
// Load the native context of the current context.
int offset =
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
- mov(scratch, FieldOperand(scratch, offset));
- mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
+ mov(scratch1, FieldOperand(scratch1, offset));
+ mov(scratch1, FieldOperand(scratch1, GlobalObject::kNativeContextOffset));
// Check the context is a native context.
if (emit_debug_code()) {
- push(scratch);
// Read the first word and compare to native_context_map.
- mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
- cmp(scratch, isolate()->factory()->native_context_map());
+ cmp(FieldOperand(scratch1, HeapObject::kMapOffset),
+ isolate()->factory()->native_context_map());
Check(equal, "JSGlobalObject::native_context should be a native context.");
- pop(scratch);
}
// Check if both contexts are the same.
- cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
+ cmp(scratch1, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
j(equal, &same_contexts);
// Compare security tokens, save holder_reg on the stack so we can use it
// as a temporary register.
//
- // TODO(119): avoid push(holder_reg)/pop(holder_reg)
- push(holder_reg);
// Check that the security token in the calling global object is
// compatible with the security token in the receiving global
// object.
- mov(holder_reg,
+ mov(scratch2,
FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
// Check the context is a native context.
if (emit_debug_code()) {
- cmp(holder_reg, isolate()->factory()->null_value());
+ cmp(scratch2, isolate()->factory()->null_value());
Check(not_equal, "JSGlobalProxy::context() should not be null.");
- push(holder_reg);
// Read the first word and compare to native_context_map(),
- mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
- cmp(holder_reg, isolate()->factory()->native_context_map());
+ cmp(FieldOperand(scratch2, HeapObject::kMapOffset),
+ isolate()->factory()->native_context_map());
Check(equal, "JSGlobalObject::native_context should be a native context.");
- pop(holder_reg);
}
int token_offset = Context::kHeaderSize +
Context::SECURITY_TOKEN_INDEX * kPointerSize;
- mov(scratch, FieldOperand(scratch, token_offset));
- cmp(scratch, FieldOperand(holder_reg, token_offset));
- pop(holder_reg);
+ mov(scratch1, FieldOperand(scratch1, token_offset));
+ cmp(scratch1, FieldOperand(scratch2, token_offset));
j(not_equal, miss);
bind(&same_contexts);
@@ -2522,6 +2518,28 @@
}
+void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
+ // Make sure the floating point stack is either empty or has depth items.
+ ASSERT(depth <= 7);
+
+ // The top-of-stack (tos) is 7 if there is one item pushed.
+ int tos = (8 - depth) % 8;
+ const int kTopMask = 0x3800;
+ push(eax);
+ fwait();
+ fnstsw_ax();
+ and_(eax, kTopMask);
+ shr(eax, 11);
+ cmp(eax, Immediate(tos));
+ Label all_ok;
+ j(equal, &all_ok);
+ Check(equal, "Unexpected FPU stack depth after instruction");
+ bind(&all_ok);
+ fnclex();
+ pop(eax);
+}
+
+
void MacroAssembler::Drop(int stack_elements) {
if (stack_elements > 0) {
add(esp, Immediate(stack_elements * kPointerSize));
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index b3dae73..159ae6e 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -548,7 +548,8 @@
// on access to global objects across environments. The holder register
// is left untouched, but the scratch register is clobbered.
void CheckAccessGlobalProxy(Register holder_reg,
- Register scratch,
+ Register scratch1,
+ Register scratch2,
Label* miss);
void GetNumberHash(Register r0, Register scratch);
@@ -806,6 +807,8 @@
return code_object_;
}
+ // Insert code to verify that the x87 stack has the specified depth (0-7)
+ void VerifyX87StackDepth(uint32_t depth);
// ---------------------------------------------------------------------------
// StatsCounter support
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index cb4b4a7..cb3c68e 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -726,33 +726,54 @@
}
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+ Handle<GlobalObject> global,
+ Handle<Name> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
+ if (Serializer::enabled()) {
+ __ mov(scratch, Immediate(cell));
+ __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+ Immediate(the_hole));
+ } else {
+ __ cmp(Operand::Cell(cell), Immediate(the_hole));
+ }
+ __ j(not_equal, miss);
+}
+
+
// 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,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label,
- Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label,
+ Label* miss_restore_name) {
// Check that the map of the object hasn't changed.
- CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
- : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK, mode);
+ miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
}
// Check that we are allowed to write this.
- if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+ if (object->GetPrototype()->IsJSObject()) {
JSObject* holder;
// holder == object indicates that no property was found.
if (lookup->holder() != *object) {
@@ -771,12 +792,18 @@
// If no property was found, and the holder (the last object in the
// prototype chain) is in slow mode, we need to do a negative lookup on the
// holder.
- if (lookup->holder() == *object &&
- !holder->HasFastProperties() &&
- !holder->IsJSGlobalProxy() &&
- !holder->IsJSGlobalObject()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ if (lookup->holder() == *object) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm,
+ Handle<GlobalObject>(GlobalObject::cast(holder)),
+ name,
+ scratch1,
+ miss_restore_name);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
}
@@ -785,7 +812,7 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+ if (object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ pop(scratch1); // Return address.
@@ -801,33 +828,29 @@
return;
}
- int index;
- if (!transition.is_null()) {
- // Update the map of the object.
- __ mov(scratch1, Immediate(transition));
- __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
+ // Update the map of the object.
+ __ mov(scratch1, Immediate(transition));
+ __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
- // Update the write barrier for the map field and pass the now unused
- // name_reg as scratch register.
- __ RecordWriteField(receiver_reg,
- HeapObject::kMapOffset,
- scratch1,
- name_reg,
- kDontSaveFPRegs,
- OMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- index = transition->instance_descriptors()->GetFieldIndex(
- transition->LastAdded());
- } else {
- index = lookup->GetFieldIndex().field_index();
- }
+ // Update the write barrier for the map field and pass the now unused
+ // name_reg as scratch register.
+ __ RecordWriteField(receiver_reg,
+ HeapObject::kMapOffset,
+ scratch1,
+ name_reg,
+ kDontSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ int index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= object->map()->inobject_properties();
+ // TODO(verwaest): Share this code as a code stub.
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -864,26 +887,71 @@
}
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
- Handle<GlobalObject> global,
- Handle<Name> name,
- Register scratch,
- Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
- GlobalObject::EnsurePropertyCell(global, name);
- ASSERT(cell->value()->IsTheHole());
- Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
- if (Serializer::enabled()) {
- __ mov(scratch, Immediate(cell));
- __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
- Immediate(the_hole));
- } else {
- __ cmp(Operand::Cell(cell), Immediate(the_hole));
+// 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,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ // Check that the map of the object hasn't changed.
+ __ CheckMap(receiver_reg, Handle<Map>(object->map()),
+ miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
}
- __ j(not_equal, miss);
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ int index = lookup->GetFieldIndex().field_index();
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ // TODO(verwaest): Share this code as a code stub.
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ mov(FieldOperand(receiver_reg, offset), value_reg);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(receiver_reg,
+ offset,
+ name_reg,
+ scratch1,
+ kDontSaveFPRegs);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array (optimistically).
+ __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ mov(FieldOperand(scratch1, offset), eax);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(scratch1,
+ offset,
+ name_reg,
+ receiver_reg,
+ kDontSaveFPRegs);
+ }
+
+ // Return the value (register eax).
+ ASSERT(value_reg.is(eax));
+ __ ret(0);
}
@@ -972,10 +1040,6 @@
} else {
bool in_new_space = heap()->InNewSpace(*prototype);
Handle<Map> current_map(current->map());
- if (in_new_space) {
- // Save the map in scratch1 for later.
- __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- }
if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
__ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
ALLOW_ELEMENT_TRANSITION_MAPS);
@@ -985,8 +1049,14 @@
// the map check so that we know that the object is actually a global
// object.
if (current->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(reg, scratch2, miss);
+ __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
}
+
+ if (in_new_space) {
+ // Save the map in scratch1 for later.
+ __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ }
+
reg = holder_reg; // From now on the object will be in holder_reg.
if (in_new_space) {
@@ -1020,7 +1090,7 @@
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
if (holder->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(reg, scratch1, miss);
+ __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
}
// If we've skipped any global objects, it's not enough to verify that
@@ -1111,7 +1181,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+ HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1119,13 +1189,6 @@
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- if (!last->HasFastProperties()) {
- __ mov(scratch2(), FieldOperand(reg, HeapObject::kMapOffset));
- __ mov(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset));
- __ cmp(scratch2(), isolate()->factory()->null_value());
- __ j(not_equal, &miss);
- }
-
HandlerFrontendFooter(success, &miss);
}
@@ -2657,7 +2720,7 @@
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(edx, ebx, &miss);
+ __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss);
}
// Stub never generated for non-global objects that require access
diff --git a/src/ic.cc b/src/ic.cc
index 515c6f7..3c33e4f 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1586,7 +1586,7 @@
switch (lookup->type()) {
case FIELD:
return isolate()->stub_cache()->ComputeStoreField(
- name, receiver, lookup, Handle<Map>::null(), strict_mode);
+ name, receiver, lookup, strict_mode);
case NORMAL:
if (receiver->IsGlobalObject()) {
// The stub generated for the global object picks the value directly
@@ -1644,7 +1644,7 @@
if (details.type() != FIELD || details.attributes() != NONE) break;
- return isolate()->stub_cache()->ComputeStoreField(
+ return isolate()->stub_cache()->ComputeStoreTransition(
name, receiver, lookup, transition, strict_mode);
}
case NONEXISTENT:
@@ -1987,7 +1987,7 @@
switch (lookup->type()) {
case FIELD:
return isolate()->stub_cache()->ComputeKeyedStoreField(
- name, receiver, lookup, Handle<Map>::null(), strict_mode);
+ name, receiver, lookup, strict_mode);
case TRANSITION: {
// Explicitly pass in the receiver map since LookupForWrite may have
// stored something else than the receiver in the holder.
@@ -1999,7 +1999,7 @@
PropertyDetails details = target_descriptors->GetDetails(descriptor);
if (details.type() == FIELD && details.attributes() == NONE) {
- return isolate()->stub_cache()->ComputeKeyedStoreField(
+ return isolate()->stub_cache()->ComputeKeyedStoreTransition(
name, receiver, lookup, transition, strict_mode);
}
// fall through.
@@ -2386,8 +2386,7 @@
ic.patch(*code);
}
- Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
- isolate->thread_local_top()->context_->builtins(), isolate);
+ Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
Object* builtin = NULL; // Initialization calms down the compiler.
switch (op) {
case Token::SUB:
@@ -2524,8 +2523,7 @@
}
}
- Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
- isolate->thread_local_top()->context_->builtins(), isolate);
+ Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
Object* builtin = NULL; // Initialization calms down the compiler.
switch (op) {
case Token::ADD:
diff --git a/src/isolate.cc b/src/isolate.cc
index 0415519..ca2c025 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -371,6 +371,12 @@
Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() {
ThreadId thread_id = ThreadId::Current();
+ return FindPerThreadDataForThread(thread_id);
+}
+
+
+Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThread(
+ ThreadId thread_id) {
PerIsolateThreadData* per_thread = NULL;
{
ScopedLock lock(process_wide_mutex_);
@@ -1140,7 +1146,7 @@
Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
if (line->length() > 0) {
line->PrintOn(out);
- fprintf(out, "\n");
+ PrintF(out, "\n");
}
}
}
@@ -1213,6 +1219,7 @@
return false;
}
+static int fatal_exception_depth = 0;
void Isolate::DoThrow(Object* exception, MessageLocation* location) {
ASSERT(!has_pending_exception());
@@ -1296,6 +1303,21 @@
thread_local_top()->pending_message_start_pos_ = location->start_pos();
thread_local_top()->pending_message_end_pos_ = location->end_pos();
}
+
+ // If the abort-on-uncaught-exception flag is specified, abort on any
+ // exception not caught by JavaScript, even when an external handler is
+ // present. This flag is intended for use by JavaScript developers, so
+ // print a user-friendly stack trace (not an internal one).
+ if (fatal_exception_depth == 0 &&
+ FLAG_abort_on_uncaught_exception &&
+ (report_exception || can_be_caught_externally)) {
+ fatal_exception_depth++;
+ PrintF(stderr,
+ "%s\n\nFROM\n",
+ *MessageHandler::GetLocalizedMessage(this, message_obj));
+ PrintCurrentStackTrace(stderr);
+ OS::Abort();
+ }
} else if (location != NULL && !location->script().is_null()) {
// We are bootstrapping and caught an error where the location is set
// and we have a script for the location.
@@ -1508,14 +1530,12 @@
Handle<Context> Isolate::native_context() {
- GlobalObject* global = thread_local_top()->context_->global_object();
- return Handle<Context>(global->native_context());
+ return Handle<Context>(context()->global_object()->native_context());
}
Handle<Context> Isolate::global_context() {
- GlobalObject* global = thread_local_top()->context_->global_object();
- return Handle<Context>(global->global_context());
+ return Handle<Context>(context()->global_object()->global_context());
}
@@ -1542,11 +1562,8 @@
char* Isolate::ArchiveThread(char* to) {
- if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
- RuntimeProfiler::IsolateExitedJS(this);
- }
- memcpy(to, reinterpret_cast<char*>(thread_local_top()),
- sizeof(ThreadLocalTop));
+ OS::MemCopy(to, reinterpret_cast<char*>(thread_local_top()),
+ sizeof(ThreadLocalTop));
InitializeThreadLocal();
clear_pending_exception();
clear_pending_message();
@@ -1556,8 +1573,8 @@
char* Isolate::RestoreThread(char* from) {
- memcpy(reinterpret_cast<char*>(thread_local_top()), from,
- sizeof(ThreadLocalTop));
+ OS::MemCopy(reinterpret_cast<char*>(thread_local_top()), from,
+ sizeof(ThreadLocalTop));
// This might be just paranoia, but it seems to be needed in case a
// thread_local_top_ is restored on a separate OS thread.
#ifdef USE_SIMULATOR
@@ -1567,9 +1584,6 @@
thread_local_top()->simulator_ = Simulator::current(this);
#endif
#endif
- if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
- RuntimeProfiler::IsolateEnteredJS(this);
- }
ASSERT(context() == NULL || context()->IsContext());
return from + sizeof(ThreadLocalTop);
}
@@ -1810,7 +1824,8 @@
if (FLAG_hydrogen_stats) GetHStatistics()->Print();
// We must stop the logger before we tear down other components.
- logger_->EnsureTickerStopped();
+ Sampler* sampler = logger_->sampler();
+ if (sampler && sampler->IsActive()) sampler->Stop();
delete deoptimizer_data_;
deoptimizer_data_ = NULL;
@@ -1826,11 +1841,6 @@
preallocated_message_space_ = NULL;
PreallocatedMemoryThreadStop();
- delete heap_profiler_;
- heap_profiler_ = NULL;
- delete cpu_profiler_;
- cpu_profiler_ = NULL;
-
if (runtime_profiler_ != NULL) {
runtime_profiler_->TearDown();
delete runtime_profiler_;
@@ -1839,6 +1849,11 @@
heap_.TearDown();
logger_->TearDown();
+ delete heap_profiler_;
+ heap_profiler_ = NULL;
+ delete cpu_profiler_;
+ cpu_profiler_ = NULL;
+
// The default isolate is re-initializable due to legacy API.
state_ = UNINITIALIZED;
}
@@ -2055,13 +2070,12 @@
date_cache_ = new DateCache();
code_stub_interface_descriptors_ =
new CodeStubInterfaceDescriptor[CodeStub::NUMBER_OF_IDS];
+ cpu_profiler_ = new CpuProfiler(this);
+ heap_profiler_ = new HeapProfiler(heap());
// Enable logging before setting up the heap
logger_->SetUp();
- cpu_profiler_ = new CpuProfiler(this);
- heap_profiler_ = new HeapProfiler(heap());
-
// Initialize other runtime facilities
#if defined(USE_SIMULATOR)
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
@@ -2177,9 +2191,16 @@
// Ensure that all stubs which need to be generated ahead of time, but
// cannot be serialized into the snapshot have been generated.
HandleScope scope(this);
- StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(this);
CodeStub::GenerateFPStubs(this);
+ StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(this);
StubFailureTrampolineStub::GenerateAheadOfTime(this);
+ // TODO(mstarzinger): The following is an ugly hack to make sure the
+ // interface descriptor is initialized even when stubs have been
+ // deserialized out of the snapshot without the graph builder.
+ FastCloneShallowArrayStub stub(FastCloneShallowArrayStub::CLONE_ELEMENTS,
+ DONT_TRACK_ALLOCATION_SITE, 0);
+ stub.InitializeInterfaceDescriptor(
+ this, code_stub_interface_descriptor(CodeStub::FastCloneShallowArray));
}
if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Start();
diff --git a/src/isolate.h b/src/isolate.h
index f7a81d3..927ad0e 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -497,6 +497,10 @@
// If one does not yet exist, return null.
PerIsolateThreadData* FindPerThreadDataForThisThread();
+ // Find the PerThread for given (isolate, thread) combination
+ // If one does not yet exist, return null.
+ PerIsolateThreadData* FindPerThreadDataForThread(ThreadId thread_id);
+
#ifdef ENABLE_DEBUGGER_SUPPORT
// Get the debugger from the default isolate. Preinitializes the
// default isolate if needed.
@@ -645,7 +649,7 @@
}
inline Address* handler_address() { return &thread_local_top_.handler_; }
- // Bottom JS entry (see StackTracer::Trace in log.cc).
+ // Bottom JS entry (see StackTracer::Trace in sampler.cc).
static Address js_entry_sp(ThreadLocalTop* thread) {
return thread->js_entry_sp_;
}
@@ -1027,23 +1031,6 @@
}
void SetCurrentVMState(StateTag state) {
- if (RuntimeProfiler::IsEnabled()) {
- // Make sure thread local top is initialized.
- ASSERT(thread_local_top_.isolate_ == this);
- StateTag current_state = thread_local_top_.current_vm_state_;
- if (current_state != JS && state == JS) {
- // Non-JS -> JS transition.
- RuntimeProfiler::IsolateEnteredJS(this);
- } else if (current_state == JS && state != JS) {
- // JS -> non-JS transition.
- RuntimeProfiler::IsolateExitedJS(this);
- } else {
- // Other types of state transitions are not interesting to the
- // runtime profiler, because they don't affect whether we're
- // in JS or not.
- ASSERT((current_state == JS) == (state == JS));
- }
- }
thread_local_top_.current_vm_state_ = state;
}
@@ -1480,7 +1467,6 @@
#define HEAP (v8::internal::Isolate::Current()->heap())
#define FACTORY (v8::internal::Isolate::Current()->factory())
#define ISOLATE (v8::internal::Isolate::Current())
-#define LOGGER (v8::internal::Isolate::Current()->logger())
// Tells whether the native context is marked with out of memory.
diff --git a/src/json-parser.h b/src/json-parser.h
index ac34c59..74850ca 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -102,9 +102,37 @@
Handle<String> ParseJsonString() {
return ScanJsonString<false>();
}
+
+ bool ParseJsonString(Handle<String> expected) {
+ int length = expected->length();
+ if (source_->length() - position_ - 1 > length) {
+ AssertNoAllocation no_gc;
+ String::FlatContent content = expected->GetFlatContent();
+ if (content.IsAscii()) {
+ ASSERT_EQ('"', c0_);
+ const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1;
+ const uint8_t* expected_chars = content.ToOneByteVector().start();
+ for (int i = 0; i < length; i++) {
+ uint8_t c0 = input_chars[i];
+ if (c0 != expected_chars[i] ||
+ c0 == '"' || c0 < 0x20 || c0 == '\\') {
+ return false;
+ }
+ }
+ if (input_chars[length] == '"') {
+ position_ = position_ + length + 1;
+ AdvanceSkipWhitespace();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
Handle<String> ParseJsonInternalizedString() {
return ScanJsonString<true>();
}
+
template <bool is_internalized>
Handle<String> ScanJsonString();
// Creates a new string and copies prefix[start..end] into the beginning
@@ -294,8 +322,13 @@
HandleScope scope(isolate());
Handle<JSObject> json_object =
factory()->NewJSObject(object_constructor(), pretenure_);
+ Handle<Map> map(json_object->map());
+ ZoneScope zone_scope(zone(), DELETE_ON_EXIT);
+ ZoneList<Handle<Object> > properties(8, zone());
ASSERT_EQ(c0_, '{');
+ bool transitioning = true;
+
AdvanceSkipWhitespace();
if (c0_ != '}') {
do {
@@ -339,24 +372,75 @@
c0_ = '"';
#endif
- Handle<String> key = ParseJsonInternalizedString();
- if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+ Handle<String> key;
+ Handle<Object> value;
- AdvanceSkipWhitespace();
- Handle<Object> value = ParseJsonValue();
- if (value.is_null()) return ReportUnexpectedCharacter();
+ // Try to follow existing transitions as long as possible. Once we stop
+ // transitioning, no transition can be found anymore.
+ if (transitioning) {
+ // First check whether there is a single expected transition. If so, try
+ // to parse it first.
+ bool follow_expected = false;
+ if (seq_ascii) {
+ key = JSObject::ExpectedTransitionKey(map);
+ follow_expected = !key.is_null() && ParseJsonString(key);
+ }
+ // If the expected transition hits, follow it.
+ if (follow_expected) {
+ map = JSObject::ExpectedTransitionTarget(map);
+ } else {
+ // If the expected transition failed, parse an internalized string and
+ // try to find a matching transition.
+ key = ParseJsonInternalizedString();
+ if (key.is_null()) return ReportUnexpectedCharacter();
- if (JSObject::TryTransitionToField(json_object, key)) {
- int index = json_object->LastAddedFieldIndex();
- json_object->FastPropertyAtPut(index, *value);
+ Handle<Map> target = JSObject::FindTransitionToField(map, key);
+ // If a transition was found, follow it and continue.
+ if (!target.is_null()) {
+ map = target;
+ } else {
+ // If no transition was found, commit the intermediate state to the
+ // object and stop transitioning.
+ JSObject::TransitionToMap(json_object, map);
+ int length = properties.length();
+ for (int i = 0; i < length; i++) {
+ json_object->FastPropertyAtPut(i, *properties[i]);
+ }
+ transitioning = false;
+ }
+ }
+ if (c0_ != ':') return ReportUnexpectedCharacter();
+
+ AdvanceSkipWhitespace();
+ value = ParseJsonValue();
+ if (value.is_null()) return ReportUnexpectedCharacter();
+
+ properties.Add(value, zone());
+ if (transitioning) continue;
} else {
- JSObject::SetLocalPropertyIgnoreAttributes(
- json_object, key, value, NONE);
+ key = ParseJsonInternalizedString();
+ if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+
+ AdvanceSkipWhitespace();
+ value = ParseJsonValue();
+ if (value.is_null()) return ReportUnexpectedCharacter();
}
+
+ JSObject::SetLocalPropertyIgnoreAttributes(
+ json_object, key, value, NONE);
} while (MatchSkipWhiteSpace(','));
if (c0_ != '}') {
return ReportUnexpectedCharacter();
}
+
+ // If we transitioned until the very end, transition the map now.
+ if (transitioning) {
+ JSObject::TransitionToMap(json_object, map);
+ int length = properties.length();
+ for (int i = 0; i < length; i++) {
+ json_object->FastPropertyAtPut(i, *properties[i]);
+ }
+ }
}
AdvanceSkipWhitespace();
return scope.CloseAndEscape(json_object);
@@ -644,22 +728,32 @@
uint32_t capacity = string_table->Capacity();
uint32_t entry = StringTable::FirstProbe(hash, capacity);
uint32_t count = 1;
+ Handle<String> result;
while (true) {
Object* element = string_table->KeyAt(entry);
if (element == isolate()->heap()->undefined_value()) {
// Lookup failure.
+ result = factory()->InternalizeOneByteString(
+ seq_source_, position_, length);
break;
}
if (element != isolate()->heap()->the_hole_value() &&
String::cast(element)->IsOneByteEqualTo(string_vector)) {
- // Lookup success, update the current position.
- position_ = position;
- // Advance past the last '"'.
- AdvanceSkipWhitespace();
- return Handle<String>(String::cast(element), isolate());
+ result = Handle<String>(String::cast(element), isolate());
+#ifdef DEBUG
+ uint32_t hash_field =
+ (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
+ ASSERT_EQ(static_cast<int>(result->Hash()),
+ static_cast<int>(hash_field >> String::kHashShift));
+#endif
+ break;
}
entry = StringTable::NextProbe(entry, count++, capacity);
}
+ position_ = position;
+ // Advance past the last '"'.
+ AdvanceSkipWhitespace();
+ return result;
}
int beg_pos = position_;
@@ -682,14 +776,10 @@
}
} while (c0_ != '"');
int length = position_ - beg_pos;
- Handle<String> result;
- if (seq_ascii && is_internalized) {
- result = factory()->InternalizeOneByteString(seq_source_, beg_pos, length);
- } else {
- result = factory()->NewRawOneByteString(length, pretenure_);
- uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
- String::WriteToFlat(*source_, dest, beg_pos, position_);
- }
+ Handle<String> result = factory()->NewRawOneByteString(length, pretenure_);
+ uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
+ String::WriteToFlat(*source_, dest, beg_pos, position_);
+
ASSERT_EQ('"', c0_);
// Advance past the last '"'.
AdvanceSkipWhitespace();
diff --git a/src/json.js b/src/json.js
index e94d3c8..b0e14e1 100644
--- a/src/json.js
+++ b/src/json.js
@@ -25,8 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// This file relies on the fact that the following declarations have been made
+// in runtime.js:
+// var $Array = global.Array;
+// var $String = global.String;
+
var $JSON = global.JSON;
+// -------------------------------------------------------------------
+
function Revive(holder, name, reviver) {
var val = holder[name];
if (IS_OBJECT(val)) {
@@ -207,14 +214,23 @@
}
+// -------------------------------------------------------------------
+
function SetUpJSON() {
%CheckIsBootstrapping();
+
+ // Set up non-enumerable properties of the JSON object.
InstallFunctions($JSON, DONT_ENUM, $Array(
"parse", JSONParse,
"stringify", JSONStringify
));
}
+SetUpJSON();
+
+
+// -------------------------------------------------------------------
+// JSON Builtins
function JSONSerializeAdapter(key, object) {
var holder = {};
@@ -222,5 +238,3 @@
// No need to pass the actual holder since there is no replacer function.
return JSONSerialize(key, holder, void 0, new InternalArray(), "", "");
}
-
-SetUpJSON();
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index b490521..fd87a80 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -624,7 +624,8 @@
index);
if (result == RE_SUCCESS) {
// Copy capture results to the start of the registers array.
- memcpy(output, raw_output, number_of_capture_registers * sizeof(int32_t));
+ OS::MemCopy(
+ output, raw_output, number_of_capture_registers * sizeof(int32_t));
}
if (result == RE_EXCEPTION) {
ASSERT(!isolate->has_pending_exception());
diff --git a/src/list-inl.h b/src/list-inl.h
index 7a84313..408859e 100644
--- a/src/list-inl.h
+++ b/src/list-inl.h
@@ -29,6 +29,7 @@
#define V8_LIST_INL_H_
#include "list.h"
+#include "platform.h"
namespace v8 {
namespace internal {
@@ -87,7 +88,7 @@
void List<T, P>::Resize(int new_capacity, P alloc) {
ASSERT_LE(length_, new_capacity);
T* new_data = NewData(new_capacity, alloc);
- memcpy(new_data, data_, length_ * sizeof(T));
+ OS::MemCopy(new_data, data_, length_ * sizeof(T));
List<T, P>::DeleteData(data_);
data_ = new_data;
capacity_ = new_capacity;
diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc
index 7049a58..7bddef7 100644
--- a/src/lithium-allocator.cc
+++ b/src/lithium-allocator.cc
@@ -1546,6 +1546,9 @@
LiveRange* current = unhandled_live_ranges_.RemoveLast();
ASSERT(UnhandledIsSorted());
LifetimePosition position = current->Start();
+#ifdef DEBUG
+ allocation_finger_ = position;
+#endif
TraceAlloc("Processing interval %d start=%d\n",
current->id(),
position.Value());
@@ -1670,6 +1673,7 @@
void LAllocator::AddToUnhandledSorted(LiveRange* range) {
if (range == NULL || range->IsEmpty()) return;
ASSERT(!range->HasRegisterAssigned() && !range->IsSpilled());
+ ASSERT(allocation_finger_.Value() <= range->Start().Value());
for (int i = unhandled_live_ranges_.length() - 1; i >= 0; --i) {
LiveRange* cur_range = unhandled_live_ranges_.at(i);
if (range->ShouldBeAllocatedBefore(cur_range)) {
@@ -1788,7 +1792,7 @@
bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
LifetimePosition free_until_pos[DoubleRegister::kMaxNumAllocatableRegisters];
- for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; i++) {
+ for (int i = 0; i < num_registers_; i++) {
free_until_pos[i] = LifetimePosition::MaxPosition();
}
@@ -1880,7 +1884,7 @@
LifetimePosition use_pos[DoubleRegister::kMaxNumAllocatableRegisters];
LifetimePosition block_pos[DoubleRegister::kMaxNumAllocatableRegisters];
- for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
+ for (int i = 0; i < num_registers_; i++) {
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
}
@@ -2000,7 +2004,15 @@
if (next_pos == NULL) {
SpillAfter(range, spill_pos);
} else {
- SpillBetween(range, spill_pos, next_pos->pos());
+ // When spilling between spill_pos and next_pos ensure that the range
+ // remains spilled at least until the start of the current live range.
+ // This guarantees that we will not introduce new unhandled ranges that
+ // start before the current range as this violates allocation invariant
+ // and will lead to an inconsistent state of active and inactive
+ // live-ranges: ranges are allocated in order of their start positions,
+ // ranges are retired from active/inactive when the start of the
+ // current live-range is larger than their end.
+ SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos());
}
if (!AllocationOk()) return;
ActiveToHandled(range);
@@ -2114,6 +2126,14 @@
void LAllocator::SpillBetween(LiveRange* range,
LifetimePosition start,
LifetimePosition end) {
+ SpillBetweenUntil(range, start, start, end);
+}
+
+
+void LAllocator::SpillBetweenUntil(LiveRange* range,
+ LifetimePosition start,
+ LifetimePosition until,
+ LifetimePosition end) {
CHECK(start.Value() < end.Value());
LiveRange* second_part = SplitRangeAt(range, start);
if (!AllocationOk()) return;
@@ -2124,7 +2144,7 @@
// and put the rest to unhandled.
LiveRange* third_part = SplitBetween(
second_part,
- second_part->Start().InstructionEnd(),
+ Max(second_part->Start().InstructionEnd(), until),
end.PrevInstruction().InstructionEnd());
if (!AllocationOk()) return;
diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h
index 70f3182..8b45531 100644
--- a/src/lithium-allocator.h
+++ b/src/lithium-allocator.h
@@ -536,11 +536,18 @@
// Spill the given life range after position pos.
void SpillAfter(LiveRange* range, LifetimePosition pos);
- // Spill the given life range after position start and up to position end.
+ // Spill the given life range after position [start] and up to position [end].
void SpillBetween(LiveRange* range,
LifetimePosition start,
LifetimePosition end);
+ // Spill the given life range after position [start] and up to position [end].
+ // Range is guaranteed to be spilled at least until position [until].
+ void SpillBetweenUntil(LiveRange* range,
+ LifetimePosition start,
+ LifetimePosition until,
+ LifetimePosition end);
+
void SplitAndSpillIntersecting(LiveRange* range);
// If we are trying to spill a range inside the loop try to
@@ -625,6 +632,10 @@
// Indicates success or failure during register allocation.
bool allocation_ok_;
+#ifdef DEBUG
+ LifetimePosition allocation_finger_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(LAllocator);
};
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 58c846a..b28cd3e 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -609,7 +609,7 @@
CompilationInfoWithZone info(script);
info.MarkAsGlobal();
// Parse and don't allow skipping lazy functions.
- if (ParserApi::Parse(&info, kNoParsingFlags)) {
+ if (Parser::Parse(&info)) {
// Compile the code.
LiveEditFunctionTracker tracker(info.isolate(), info.function());
if (Compiler::MakeCodeForLiveEdit(&info)) {
@@ -1435,8 +1435,8 @@
// Copy the data.
int curently_used_size =
static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
- memmove(new_buffer + new_buffer_size - curently_used_size,
- reloc_info_writer_.pos(), curently_used_size);
+ OS::MemMove(new_buffer + new_buffer_size - curently_used_size,
+ reloc_info_writer_.pos(), curently_used_size);
reloc_info_writer_.Reposition(
new_buffer + new_buffer_size - curently_used_size,
@@ -1488,7 +1488,7 @@
if (buffer.length() == code->relocation_size()) {
// Simply patch relocation area of code.
- memcpy(code->relocation_start(), buffer.start(), buffer.length());
+ OS::MemCopy(code->relocation_start(), buffer.start(), buffer.length());
return code;
} else {
// Relocation info section now has different size. We cannot simply
@@ -1761,9 +1761,9 @@
StackFrame* pre_pre_frame = frames[top_frame_index - 2];
- memmove(padding_start + kPointerSize - shortage_bytes,
- padding_start + kPointerSize,
- Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
+ OS::MemMove(padding_start + kPointerSize - shortage_bytes,
+ padding_start + kPointerSize,
+ Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
pre_pre_frame->SetCallerFp(pre_top_frame->fp());
diff --git a/src/log-utils.cc b/src/log-utils.cc
index 45ac403..cef7dba 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -167,8 +167,9 @@
// Open the low-level log file.
size_t len = strlen(name);
ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLowLevelLogExt)));
- memcpy(ll_name.start(), name, len);
- memcpy(ll_name.start() + len, kLowLevelLogExt, sizeof(kLowLevelLogExt));
+ OS::MemCopy(ll_name.start(), name, len);
+ OS::MemCopy(ll_name.start() + len,
+ kLowLevelLogExt, sizeof(kLowLevelLogExt));
ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
setvbuf(ll_output_handle_, NULL, _IOFBF, kLowLevelLogBufferSize);
}
diff --git a/src/log.cc b/src/log.cc
index 9438537..1538894 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -112,45 +112,6 @@
//
-// StackTracer implementation
-//
-DISABLE_ASAN void StackTracer::Trace(Isolate* isolate, TickSample* sample) {
- ASSERT(isolate->IsInitialized());
-
- // Avoid collecting traces while doing GC.
- if (sample->state == GC) return;
-
- const Address js_entry_sp =
- Isolate::js_entry_sp(isolate->thread_local_top());
- if (js_entry_sp == 0) {
- // Not executing JS now.
- return;
- }
-
- const Address callback = isolate->external_callback();
- if (callback != NULL) {
- sample->external_callback = callback;
- sample->has_external_callback = true;
- } else {
- // Sample potential return address value for frameless invocation of
- // stubs (we'll figure out later, if this value makes sense).
- sample->tos = Memory::Address_at(sample->sp);
- sample->has_external_callback = false;
- }
-
- SafeStackTraceFrameIterator it(isolate,
- sample->fp, sample->sp,
- sample->sp, js_entry_sp);
- int i = 0;
- while (!it.done() && i < TickSample::kMaxFramesCount) {
- sample->stack[i++] = it.frame()->pc();
- it.Advance();
- }
- sample->frames_count = i;
-}
-
-
-//
// Ticker used to provide ticks to the profiler and the sliding state
// window.
//
@@ -179,11 +140,6 @@
if (IsActive()) Stop();
}
- protected:
- virtual void DoSampleStack(TickSample* sample) {
- StackTracer::Trace(isolate(), sample);
- }
-
private:
Profiler* profiler_;
};
@@ -216,9 +172,10 @@
Start();
// Register to get ticks.
- LOGGER->ticker_->SetProfiler(this);
+ Logger* logger = isolate_->logger();
+ logger->ticker_->SetProfiler(this);
- LOGGER->ProfilerBeginEvent();
+ logger->ProfilerBeginEvent();
}
@@ -226,7 +183,7 @@
if (!engaged_) return;
// Stop receiving ticks.
- LOGGER->ticker_->ClearProfiler();
+ isolate_->logger()->ticker_->ClearProfiler();
// Terminate the worker thread by setting running_ to false,
// inserting a fake element in the queue and then wait for
@@ -406,7 +363,7 @@
void AppendBytes(const char* bytes, int size) {
size = Min(size, kUtf8BufferSize - utf8_pos_);
- memcpy(utf8_buffer_ + utf8_pos_, bytes, size);
+ OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
utf8_pos_ += size;
}
@@ -778,11 +735,10 @@
}
-void Logger::LogRuntime(Isolate* isolate,
- Vector<const char> format,
+void Logger::LogRuntime(Vector<const char> format,
JSArray* args) {
if (!log_->IsEnabled() || !FLAG_log_runtime) return;
- HandleScope scope(isolate);
+ HandleScope scope(isolate_);
LogMessageBuilder msg(this);
for (int i = 0; i < format.length(); i++) {
char c = format[i];
@@ -899,12 +855,12 @@
void Logger::NewEventStatic(const char* name, void* object, size_t size) {
- LOGGER->NewEvent(name, object, size);
+ Isolate::Current()->logger()->NewEvent(name, object, size);
}
void Logger::DeleteEventStatic(const char* name, void* object) {
- LOGGER->DeleteEvent(name, object);
+ Isolate::Current()->logger()->DeleteEvent(name, object);
}
void Logger::CallbackEventInternal(const char* prefix, Name* name,
@@ -1492,13 +1448,7 @@
msg.Append(',');
msg.AppendAddress(sample->sp);
msg.Append(",%ld", static_cast<int>(OS::Ticks() - epoch_));
- if (sample->has_external_callback) {
- msg.Append(",1,");
- msg.AppendAddress(sample->external_callback);
- } else {
- msg.Append(",0,");
- msg.AppendAddress(sample->tos);
- }
+ msg.AppendAddress(sample->external_callback);
msg.Append(",%d", static_cast<int>(sample->state));
if (overflow) {
msg.Append(",overflow");
@@ -1560,11 +1510,6 @@
}
-bool Logger::IsProfilerSamplerActive() {
- return ticker_->IsActive();
-}
-
-
class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
public:
EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
@@ -1937,17 +1882,6 @@
}
-void Logger::EnsureTickerStarted() {
- ASSERT(ticker_ != NULL);
- if (!ticker_->IsActive()) ticker_->Start();
-}
-
-
-void Logger::EnsureTickerStopped() {
- if (ticker_ != NULL && ticker_->IsActive()) ticker_->Stop();
-}
-
-
FILE* Logger::TearDown() {
if (!is_initialized_) return NULL;
is_initialized_ = false;
@@ -1965,65 +1899,4 @@
return log_->Close();
}
-
-// Protects the state below.
-static Mutex* active_samplers_mutex = NULL;
-
-List<Sampler*>* SamplerRegistry::active_samplers_ = NULL;
-
-
-void SamplerRegistry::SetUp() {
- if (!active_samplers_mutex) {
- active_samplers_mutex = OS::CreateMutex();
- }
-}
-
-
-bool SamplerRegistry::IterateActiveSamplers(VisitSampler func, void* param) {
- ScopedLock lock(active_samplers_mutex);
- for (int i = 0;
- ActiveSamplersExist() && i < active_samplers_->length();
- ++i) {
- func(active_samplers_->at(i), param);
- }
- return ActiveSamplersExist();
-}
-
-
-static void ComputeCpuProfiling(Sampler* sampler, void* flag_ptr) {
- bool* flag = reinterpret_cast<bool*>(flag_ptr);
- *flag |= sampler->IsProfiling();
-}
-
-
-SamplerRegistry::State SamplerRegistry::GetState() {
- bool flag = false;
- if (!IterateActiveSamplers(&ComputeCpuProfiling, &flag)) {
- return HAS_NO_SAMPLERS;
- }
- return flag ? HAS_CPU_PROFILING_SAMPLERS : HAS_SAMPLERS;
-}
-
-
-void SamplerRegistry::AddActiveSampler(Sampler* sampler) {
- ASSERT(sampler->IsActive());
- ScopedLock lock(active_samplers_mutex);
- if (active_samplers_ == NULL) {
- active_samplers_ = new List<Sampler*>;
- } else {
- ASSERT(!active_samplers_->Contains(sampler));
- }
- active_samplers_->Add(sampler);
-}
-
-
-void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) {
- ASSERT(sampler->IsActive());
- ScopedLock lock(active_samplers_mutex);
- ASSERT(active_samplers_ != NULL);
- bool removed = active_samplers_->RemoveElement(sampler);
- ASSERT(removed);
- USE(removed);
-}
-
} } // namespace v8::internal
diff --git a/src/log.h b/src/log.h
index a5eddc7..2683330 100644
--- a/src/log.h
+++ b/src/log.h
@@ -74,6 +74,7 @@
class LogMessageBuilder;
class Profiler;
class Semaphore;
+struct TickSample;
class Ticker;
class Isolate;
class PositionsRecorder;
@@ -168,9 +169,6 @@
void SetCodeEventHandler(uint32_t options,
JitCodeEventHandler event_handler);
- void EnsureTickerStarted();
- void EnsureTickerStopped();
-
Sampler* sampler();
// Frees resources acquired in SetUp.
@@ -327,7 +325,7 @@
void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
// Log an event reported from generated code
- void LogRuntime(Isolate* isolate, Vector<const char> format, JSArray* args);
+ void LogRuntime(Vector<const char> format, JSArray* args);
bool is_logging() {
return logging_nesting_ > 0;
@@ -448,9 +446,6 @@
void UncheckedIntEvent(const char* name, int value);
void UncheckedIntPtrTEvent(const char* name, intptr_t value);
- // Returns whether profiler's sampler is active.
- bool IsProfilerSamplerActive();
-
Isolate* isolate_;
// The sampler used by the profiler and the sliding state window.
@@ -471,7 +466,6 @@
friend class LogMessageBuilder;
friend class TimeLog;
friend class Profiler;
- friend class StackTracer;
friend class VMState;
friend class LoggerTestHelper;
@@ -510,46 +504,6 @@
};
-// Process wide registry of samplers.
-class SamplerRegistry : public AllStatic {
- public:
- enum State {
- HAS_NO_SAMPLERS,
- HAS_SAMPLERS,
- HAS_CPU_PROFILING_SAMPLERS
- };
-
- static void SetUp();
-
- typedef void (*VisitSampler)(Sampler*, void*);
-
- static State GetState();
-
- // Iterates over all active samplers keeping the internal lock held.
- // Returns whether there are any active samplers.
- static bool IterateActiveSamplers(VisitSampler func, void* param);
-
- // Adds/Removes an active sampler.
- static void AddActiveSampler(Sampler* sampler);
- static void RemoveActiveSampler(Sampler* sampler);
-
- private:
- static bool ActiveSamplersExist() {
- return active_samplers_ != NULL && !active_samplers_->is_empty();
- }
-
- static List<Sampler*>* active_samplers_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(SamplerRegistry);
-};
-
-
-// Class that extracts stack trace, used for profiling.
-class StackTracer : public AllStatic {
- public:
- static void Trace(Isolate* isolate, TickSample* sample);
-};
-
} } // namespace v8::internal
diff --git a/src/macro-assembler.h b/src/macro-assembler.h
index 55dccfa..9fdf2ee 100644
--- a/src/macro-assembler.h
+++ b/src/macro-assembler.h
@@ -51,7 +51,9 @@
// Align the allocation to a multiple of kDoubleSize
DOUBLE_ALIGNMENT = 1 << 3,
// Directly allocate in old pointer space
- PRETENURE_OLD_POINTER_SPACE = 1 << 4
+ PRETENURE_OLD_POINTER_SPACE = 1 << 4,
+ // Directly allocate in old data space
+ PRETENURE_OLD_DATA_SPACE = 1 << 5
};
@@ -175,17 +177,26 @@
public:
static ExternalReference GetAllocationTopReference(
Isolate* isolate, AllocationFlags flags) {
- return ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) ?
- ExternalReference::old_pointer_space_allocation_top_address(isolate) :
- ExternalReference::new_space_allocation_top_address(isolate);
+ if ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) {
+ return ExternalReference::old_pointer_space_allocation_top_address(
+ isolate);
+ } else if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+ return ExternalReference::old_data_space_allocation_top_address(isolate);
+ }
+ return ExternalReference::new_space_allocation_top_address(isolate);
}
static ExternalReference GetAllocationLimitReference(
Isolate* isolate, AllocationFlags flags) {
- return ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) ?
- ExternalReference::old_pointer_space_allocation_limit_address(isolate) :
- ExternalReference::new_space_allocation_limit_address(isolate);
+ if ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) {
+ return ExternalReference::old_pointer_space_allocation_limit_address(
+ isolate);
+ } else if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+ return ExternalReference::old_data_space_allocation_limit_address(
+ isolate);
+ }
+ return ExternalReference::new_space_allocation_limit_address(isolate);
}
};
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 7503f24..f49179f 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -672,8 +672,8 @@
return 0;
}
- FreeList::SizeStats sizes;
- space->CountFreeListItems(p, &sizes);
+ PagedSpace::SizeStats sizes;
+ space->ObtainFreeListStatistics(p, &sizes);
intptr_t ratio;
intptr_t ratio_threshold;
@@ -812,8 +812,8 @@
if (!p->WasSwept()) {
free_bytes = (p->area_size() - p->LiveBytes());
} else {
- FreeList::SizeStats sizes;
- space->CountFreeListItems(p, &sizes);
+ PagedSpace::SizeStats sizes;
+ space->ObtainFreeListStatistics(p, &sizes);
free_bytes = sizes.Total();
}
@@ -3125,8 +3125,6 @@
void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
- Heap::RelocationLock relocation_lock(heap());
-
bool code_slots_filtering_required;
{ GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE);
code_slots_filtering_required = MarkInvalidatedCode();
diff --git a/src/math.js b/src/math.js
index 0e02541..e5ab70c 100644
--- a/src/math.js
+++ b/src/math.js
@@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// This file relies on the fact that the following declarations have been made
+// in runtime.js:
+// var $Object = global.Object;
// Keep reference to original values of some global properties. This
// has the added benefit that the code in this file is isolated from
@@ -35,10 +38,9 @@
// Instance class name can only be set on functions. That is the only
// purpose for MathConstructor.
function MathConstructor() {}
-%FunctionSetInstanceClassName(MathConstructor, 'Math');
var $Math = new MathConstructor();
-%SetPrototype($Math, $Object.prototype);
-%SetProperty(global, "Math", $Math, DONT_ENUM);
+
+// -------------------------------------------------------------------
// ECMA 262 - 15.8.2.1
function MathAbs(x) {
@@ -216,6 +218,11 @@
function SetUpMath() {
%CheckIsBootstrapping();
+
+ %SetPrototype($Math, $Object.prototype);
+ %SetProperty(global, "Math", $Math, DONT_ENUM);
+ %FunctionSetInstanceClassName(MathConstructor, 'Math');
+
// Set up math constants.
// ECMA-262, section 15.8.1.1.
%OptimizeObjectForAddingMultipleProperties($Math, 8);
diff --git a/src/messages.js b/src/messages.js
index d51d384..67fe3cc 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -98,9 +98,13 @@
observe_callback_frozen: ["Object.observe cannot deliver to a frozen function object"],
observe_type_non_string: ["Invalid changeRecord with non-string 'type' property"],
observe_notify_non_notifier: ["notify called on non-notifier object"],
+ proto_poison_pill: ["Generic use of __proto__ accessor not allowed"],
// RangeError
invalid_array_length: ["Invalid array length"],
invalid_array_buffer_length: ["Invalid array buffer length"],
+ invalid_typed_array_offset: ["Start offset is too large"],
+ invalid_typed_array_length: ["Length is too large"],
+ invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
stack_overflow: ["Maximum call stack size exceeded"],
invalid_time_value: ["Invalid time value"],
// SyntaxError
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index 9c9f611..d922bfa 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -81,29 +81,17 @@
int Register::NumAllocatableRegisters() {
- if (CpuFeatures::IsSupported(FPU)) {
return kMaxNumAllocatableRegisters;
- } else {
- return kMaxNumAllocatableRegisters - kGPRsPerNonFPUDouble;
- }
}
int DoubleRegister::NumRegisters() {
- if (CpuFeatures::IsSupported(FPU)) {
return FPURegister::kMaxNumRegisters;
- } else {
- return 1;
- }
}
int DoubleRegister::NumAllocatableRegisters() {
- if (CpuFeatures::IsSupported(FPU)) {
return FPURegister::kMaxNumAllocatableRegisters;
- } else {
- return 1;
- }
}
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index c255d0f..e36b97f 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -80,29 +80,24 @@
const char* DoubleRegister::AllocationIndexToString(int index) {
- if (CpuFeatures::IsSupported(FPU)) {
- ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
- const char* const names[] = {
- "f0",
- "f2",
- "f4",
- "f6",
- "f8",
- "f10",
- "f12",
- "f14",
- "f16",
- "f18",
- "f20",
- "f22",
- "f24",
- "f26"
- };
- return names[index];
- } else {
- ASSERT(index == 0);
- return "sfpd0";
- }
+ ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
+ const char* const names[] = {
+ "f0",
+ "f2",
+ "f4",
+ "f6",
+ "f8",
+ "f10",
+ "f12",
+ "f14",
+ "f16",
+ "f18",
+ "f20",
+ "f22",
+ "f24",
+ "f26"
+ };
+ return names[index];
}
@@ -127,10 +122,8 @@
// If the compiler is allowed to use fpu then we can use fpu too in our
// code generation.
#if !defined(__mips__)
- // For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled.
- if (FLAG_enable_fpu) {
- supported_ |= static_cast<uint64_t>(1) << FPU;
- }
+ // For the simulator build, use FPU.
+ supported_ |= static_cast<uint64_t>(1) << FPU;
#else
// Probe for additional features not already known to be available.
if (OS::MipsCpuHasFeature(FPU)) {
@@ -876,7 +869,6 @@
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
- ASSERT(IsEnabled(FPU));
Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
| (fd.code() << kFdShift) | func;
emit(instr);
@@ -890,7 +882,6 @@
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
- ASSERT(IsEnabled(FPU));
Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
| (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
emit(instr);
@@ -904,7 +895,6 @@
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
- ASSERT(IsEnabled(FPU));
Instr instr = opcode | fmt | (rt.code() << kRtShift)
| (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
emit(instr);
@@ -917,7 +907,6 @@
FPUControlRegister fs,
SecondaryField func) {
ASSERT(fs.is_valid() && rt.is_valid());
- ASSERT(IsEnabled(FPU));
Instr instr =
opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
emit(instr);
@@ -952,7 +941,6 @@
FPURegister ft,
int32_t j) {
ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
- ASSERT(IsEnabled(FPU));
Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
| (j & kImm16Mask);
emit(instr);
@@ -1679,7 +1667,7 @@
void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
uint64_t i;
- memcpy(&i, &d, 8);
+ OS::MemCopy(&i, &d, 8);
*lo = i & 0xffffffff;
*hi = i >> 32;
@@ -1874,7 +1862,6 @@
// Conditions.
void Assembler::c(FPUCondition cond, SecondaryField fmt,
FPURegister fs, FPURegister ft, uint16_t cc) {
- ASSERT(IsEnabled(FPU));
ASSERT(is_uint3(cc));
ASSERT((fmt & ~(31 << kRsShift)) == 0);
Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
@@ -1885,7 +1872,6 @@
void Assembler::fcmp(FPURegister src1, const double src2,
FPUCondition cond) {
- ASSERT(IsEnabled(FPU));
ASSERT(src2 == 0.0);
mtc1(zero_reg, f14);
cvt_d_w(f14, f14);
@@ -1894,7 +1880,6 @@
void Assembler::bc1f(int16_t offset, uint16_t cc) {
- ASSERT(IsEnabled(FPU));
ASSERT(is_uint3(cc));
Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
emit(instr);
@@ -1902,7 +1887,6 @@
void Assembler::bc1t(int16_t offset, uint16_t cc) {
- ASSERT(IsEnabled(FPU));
ASSERT(is_uint3(cc));
Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
emit(instr);
@@ -1997,9 +1981,9 @@
// Copy the data.
int pc_delta = desc.buffer - buffer_;
int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
- memmove(desc.buffer, buffer_, desc.instr_size);
- memmove(reloc_info_writer.pos() + rc_delta,
- reloc_info_writer.pos(), desc.reloc_size);
+ OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+ OS::MemMove(reloc_info_writer.pos() + rc_delta,
+ reloc_info_writer.pos(), desc.reloc_size);
// Switch buffers.
DeleteArray(buffer_);
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index 9d3d39b..d12c0da 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -74,7 +74,6 @@
static const int kNumRegisters = v8::internal::kNumRegisters;
static const int kMaxNumAllocatableRegisters = 14; // v0 through t7.
static const int kSizeInBytes = 4;
- static const int kGPRsPerNonFPUDouble = 2;
inline static int NumAllocatableRegisters();
@@ -300,9 +299,6 @@
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
-const Register sfpd_lo = { kRegister_t6_Code };
-const Register sfpd_hi = { kRegister_t7_Code };
-
// Register aliases.
// cp is assumed to be a callee saved register.
// Defined using #define instead of "static const Register&" because Clang
@@ -403,7 +399,6 @@
// Check whether a feature is supported by the target CPU.
static bool IsSupported(CpuFeature f) {
ASSERT(initialized_);
- if (f == FPU && !FLAG_enable_fpu) return false;
return (supported_ & (1u << f)) != 0;
}
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 37d7720..cbe2048 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_MIPS)
#include "bootstrapper.h"
+#include "builtins-decls.h"
#include "code-stubs.h"
#include "codegen.h"
#include "regexp-macro-assembler.h"
@@ -39,6 +40,18 @@
namespace internal {
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { a3, a2, a1 };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->stack_parameter_count_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -134,7 +147,6 @@
Label* rhs_not_nan,
Label* slow,
bool strict);
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc);
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
Register lhs,
Register rhs);
@@ -183,9 +195,7 @@
__ IncrementCounter(counters->fast_new_closure_total(), 1, t2, t3);
- int map_index = (language_mode_ == CLASSIC_MODE)
- ? Context::FUNCTION_MAP_INDEX
- : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+ int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
// Compute the function map in the current native context and set that
// as the map of the allocated object.
@@ -402,147 +412,6 @@
}
-static void GenerateFastCloneShallowArrayCommon(
- MacroAssembler* masm,
- int length,
- FastCloneShallowArrayStub::Mode mode,
- AllocationSiteMode allocation_site_mode,
- Label* fail) {
- // Registers on entry:
- // a3: boilerplate literal array.
- ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
- // All sizes here are multiples of kPointerSize.
- int elements_size = 0;
- if (length > 0) {
- elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
- ? FixedDoubleArray::SizeFor(length)
- : FixedArray::SizeFor(length);
- }
-
- int size = JSArray::kSize;
- int allocation_info_start = size;
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- size += AllocationSiteInfo::kSize;
- }
- size += elements_size;
-
- // Allocate both the JS array and the elements array in one big
- // allocation. This avoids multiple limit checks.
- __ Allocate(size, v0, a1, a2, fail, TAG_OBJECT);
-
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ li(a2, Operand(Handle<Map>(masm->isolate()->heap()->
- allocation_site_info_map())));
- __ sw(a2, FieldMemOperand(v0, allocation_info_start));
- __ sw(a3, FieldMemOperand(v0, allocation_info_start + kPointerSize));
- }
-
- // Copy the JS array part.
- for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
- if ((i != JSArray::kElementsOffset) || (length == 0)) {
- __ lw(a1, FieldMemOperand(a3, i));
- __ sw(a1, FieldMemOperand(v0, i));
- }
- }
-
- if (length > 0) {
- // Get hold of the elements array of the boilerplate and setup the
- // elements pointer in the resulting object.
- __ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ Addu(a2, v0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
- } else {
- __ Addu(a2, v0, Operand(JSArray::kSize));
- }
- __ sw(a2, FieldMemOperand(v0, JSArray::kElementsOffset));
-
- // Copy the elements array.
- ASSERT((elements_size % kPointerSize) == 0);
- __ CopyFields(a2, a3, a1.bit(), elements_size / kPointerSize);
- }
-}
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
- // Stack layout on entry:
- //
- // [sp]: constant elements.
- // [sp + kPointerSize]: literal index.
- // [sp + (2 * kPointerSize)]: literals array.
-
- // Load boilerplate object into r3 and check if we need to create a
- // boilerplate.
- Label slow_case;
- __ lw(a3, MemOperand(sp, 2 * kPointerSize));
- __ lw(a0, MemOperand(sp, 1 * kPointerSize));
- __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t0, a3, t0);
- __ lw(a3, MemOperand(t0));
- __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
- __ Branch(&slow_case, eq, a3, Operand(t1));
-
- FastCloneShallowArrayStub::Mode mode = mode_;
- if (mode == CLONE_ANY_ELEMENTS) {
- Label double_elements, check_fast_elements;
- __ lw(v0, FieldMemOperand(a3, JSArray::kElementsOffset));
- __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
- __ LoadRoot(t1, Heap::kFixedCOWArrayMapRootIndex);
- __ Branch(&check_fast_elements, ne, v0, Operand(t1));
- GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- // Return and remove the on-stack parameters.
- __ DropAndRet(3);
-
- __ bind(&check_fast_elements);
- __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
- __ Branch(&double_elements, ne, v0, Operand(t1));
- GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- // Return and remove the on-stack parameters.
- __ DropAndRet(3);
-
- __ bind(&double_elements);
- mode = CLONE_DOUBLE_ELEMENTS;
- // Fall through to generate the code to handle double elements.
- }
-
- if (FLAG_debug_code) {
- const char* message;
- Heap::RootListIndex expected_map_index;
- if (mode == CLONE_ELEMENTS) {
- message = "Expected (writable) fixed array";
- expected_map_index = Heap::kFixedArrayMapRootIndex;
- } else if (mode == CLONE_DOUBLE_ELEMENTS) {
- message = "Expected (writable) fixed double array";
- expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
- } else {
- ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
- message = "Expected copy-on-write fixed array";
- expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
- }
- __ push(a3);
- __ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
- __ lw(a3, FieldMemOperand(a3, HeapObject::kMapOffset));
- __ LoadRoot(at, expected_map_index);
- __ Assert(eq, message, a3, Operand(at));
- __ pop(a3);
- }
-
- GenerateFastCloneShallowArrayCommon(masm, length_, mode,
- allocation_site_mode_,
- &slow_case);
-
- // Return and remove the on-stack parameters.
- __ DropAndRet(3);
-
- __ bind(&slow_case);
- __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
// Takes a Smi and converts to an IEEE 64 bit floating point value in two
// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
@@ -646,30 +515,15 @@
FloatingPointHelper::Destination destination,
Register scratch1,
Register scratch2) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ sra(scratch1, a0, kSmiTagSize);
- __ mtc1(scratch1, f14);
- __ cvt_d_w(f14, f14);
- __ sra(scratch1, a1, kSmiTagSize);
- __ mtc1(scratch1, f12);
- __ cvt_d_w(f12, f12);
- if (destination == kCoreRegisters) {
- __ Move(a2, a3, f14);
- __ Move(a0, a1, f12);
- }
- } else {
- ASSERT(destination == kCoreRegisters);
- // Write Smi from a0 to a3 and a2 in double format.
- __ mov(scratch1, a0);
- ConvertToDoubleStub stub1(a3, a2, scratch1, scratch2);
- __ push(ra);
- __ Call(stub1.GetCode(masm->isolate()));
- // Write Smi from a1 to a1 and a0 in double format.
- __ mov(scratch1, a1);
- ConvertToDoubleStub stub2(a1, a0, scratch1, scratch2);
- __ Call(stub2.GetCode(masm->isolate()));
- __ pop(ra);
+ __ sra(scratch1, a0, kSmiTagSize);
+ __ mtc1(scratch1, f14);
+ __ cvt_d_w(f14, f14);
+ __ sra(scratch1, a1, kSmiTagSize);
+ __ mtc1(scratch1, f12);
+ __ cvt_d_w(f12, f12);
+ if (destination == kCoreRegisters) {
+ __ Move(a2, a3, f14);
+ __ Move(a0, a1, f12);
}
}
@@ -684,8 +538,6 @@
Register scratch1,
Register scratch2,
Label* not_number) {
- ASSERT(!object.is(dst1) && !object.is(dst2));
-
__ AssertRootValue(heap_number_map,
Heap::kHeapNumberMapRootIndex,
"HeapNumberMap register clobbered.");
@@ -698,9 +550,7 @@
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
// Handle loading a double from a heap number.
- if (CpuFeatures::IsSupported(FPU) &&
- destination == kFPURegisters) {
- CpuFeatureScope scope(masm, FPU);
+ if (destination == kFPURegisters) {
// Load the double from tagged HeapNumber to double register.
// ARM uses a workaround here because of the unaligned HeapNumber
@@ -718,25 +568,13 @@
// Handle loading a double from a smi.
__ bind(&is_smi);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Convert smi to double using FPU instructions.
- __ mtc1(scratch1, dst);
- __ cvt_d_w(dst, dst);
- if (destination == kCoreRegisters) {
- // Load the converted smi to dst1 and dst2 in double format.
- __ Move(dst1, dst2, dst);
- }
- } else {
- ASSERT(destination == kCoreRegisters);
- // Write smi to dst1 and dst2 double format.
- __ mov(scratch1, object);
- ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
- __ push(ra);
- __ Call(stub.GetCode(masm->isolate()));
- __ pop(ra);
+ // Convert smi to double using FPU instructions.
+ __ mtc1(scratch1, dst);
+ __ cvt_d_w(dst, dst);
+ if (destination == kCoreRegisters) {
+ // Load the converted smi to dst1 and dst2 in double format.
+ __ Move(dst1, dst2, dst);
}
-
__ bind(&done);
}
@@ -792,74 +630,11 @@
ASSERT(!int_scratch.is(dst_mantissa));
ASSERT(!int_scratch.is(dst_exponent));
- Label done;
-
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ mtc1(int_scratch, single_scratch);
- __ cvt_d_w(double_dst, single_scratch);
- if (destination == kCoreRegisters) {
- __ Move(dst_mantissa, dst_exponent, double_dst);
- }
- } else {
- Label fewer_than_20_useful_bits;
- // Expected output:
- // | dst_exponent | dst_mantissa |
- // | s | exp | mantissa |
-
- // Check for zero.
- __ mov(dst_exponent, int_scratch);
- __ mov(dst_mantissa, int_scratch);
- __ Branch(&done, eq, int_scratch, Operand(zero_reg));
-
- // Preload the sign of the value.
- __ And(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask));
- // Get the absolute value of the object (as an unsigned integer).
- Label skip_sub;
- __ Branch(&skip_sub, ge, dst_exponent, Operand(zero_reg));
- __ Subu(int_scratch, zero_reg, int_scratch);
- __ bind(&skip_sub);
-
- // Get mantissa[51:20].
-
- // Get the position of the first set bit.
- __ Clz(dst_mantissa, int_scratch);
- __ li(scratch2, 31);
- __ Subu(dst_mantissa, scratch2, dst_mantissa);
-
- // Set the exponent.
- __ Addu(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
- __ Ins(dst_exponent, scratch2,
- HeapNumber::kExponentShift, HeapNumber::kExponentBits);
-
- // Clear the first non null bit.
- __ li(scratch2, Operand(1));
- __ sllv(scratch2, scratch2, dst_mantissa);
- __ li(at, -1);
- __ Xor(scratch2, scratch2, at);
- __ And(int_scratch, int_scratch, scratch2);
-
- // Get the number of bits to set in the lower part of the mantissa.
- __ Subu(scratch2, dst_mantissa,
- Operand(HeapNumber::kMantissaBitsInTopWord));
- __ Branch(&fewer_than_20_useful_bits, lt, scratch2, Operand(zero_reg));
- // Set the higher 20 bits of the mantissa.
- __ srlv(at, int_scratch, scratch2);
- __ or_(dst_exponent, dst_exponent, at);
- __ li(at, 32);
- __ subu(scratch2, at, scratch2);
- __ sllv(dst_mantissa, int_scratch, scratch2);
- __ Branch(&done);
-
- __ bind(&fewer_than_20_useful_bits);
- __ li(at, HeapNumber::kMantissaBitsInTopWord);
- __ subu(scratch2, at, dst_mantissa);
- __ sllv(scratch2, int_scratch, scratch2);
- __ Or(dst_exponent, dst_exponent, scratch2);
- // Set dst_mantissa to 0.
- __ mov(dst_mantissa, zero_reg);
+ __ mtc1(int_scratch, single_scratch);
+ __ cvt_d_w(double_dst, single_scratch);
+ if (destination == kCoreRegisters) {
+ __ Move(dst_mantissa, dst_exponent, double_dst);
}
- __ bind(&done);
}
@@ -880,10 +655,6 @@
ASSERT(!heap_number_map.is(object) &&
!heap_number_map.is(scratch1) &&
!heap_number_map.is(scratch2));
- // ARM uses pop/push and Ldlr to save dst_* and probably object registers in
- // softfloat path. On MIPS there is no ldlr, 1st lw instruction may overwrite
- // object register making the 2nd lw invalid.
- ASSERT(!object.is(dst_mantissa) && !object.is(dst_exponent));
Label done, obj_is_not_smi;
@@ -900,46 +671,23 @@
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
// Load the number.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Load the double value.
- __ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
+ // Load the double value.
+ __ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
- Register except_flag = scratch2;
- __ EmitFPUTruncate(kRoundToZero,
- scratch1,
- double_dst,
- at,
- double_scratch,
- except_flag,
- kCheckForInexactConversion);
+ Register except_flag = scratch2;
+ __ EmitFPUTruncate(kRoundToZero,
+ scratch1,
+ double_dst,
+ at,
+ double_scratch,
+ except_flag,
+ kCheckForInexactConversion);
- // Jump to not_int32 if the operation did not succeed.
- __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
-
- if (destination == kCoreRegisters) {
- __ Move(dst_mantissa, dst_exponent, double_dst);
- }
- } else {
- // Load the double value in the destination registers.
- __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
-
- // Check for 0 and -0.
- __ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask));
- __ Or(scratch1, scratch1, Operand(dst_mantissa));
- __ Branch(&done, eq, scratch1, Operand(zero_reg));
-
- // Check that the value can be exactly represented by a 32-bit integer.
- // Jump to not_int32 if that's not the case.
- DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
- not_int32);
-
- // dst_* were trashed. Reload the double value.
- __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+ // Jump to not_int32 if the operation did not succeed.
+ __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
+ if (destination == kCoreRegisters) {
+ __ Move(dst_mantissa, dst_exponent, double_dst);
}
-
__ bind(&done);
}
@@ -972,53 +720,20 @@
// Object is a heap number.
// Convert the floating point value to a 32-bit integer.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Load the double value.
- __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
+ // Load the double value.
+ __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
- Register except_flag = scratch2;
- __ EmitFPUTruncate(kRoundToZero,
- dst,
- double_scratch0,
- scratch1,
- double_scratch1,
- except_flag,
- kCheckForInexactConversion);
+ Register except_flag = scratch2;
+ __ EmitFPUTruncate(kRoundToZero,
+ dst,
+ double_scratch0,
+ scratch1,
+ double_scratch1,
+ except_flag,
+ kCheckForInexactConversion);
- // Jump to not_int32 if the operation did not succeed.
- __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
- } else {
- // Load the double value in the destination registers.
- __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ lw(scratch1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
-
- // Check for 0 and -0.
- __ And(dst, scratch1, Operand(~HeapNumber::kSignMask));
- __ Or(dst, scratch2, Operand(dst));
- __ Branch(&done, eq, dst, Operand(zero_reg));
-
- DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
-
- // Registers state after DoubleIs32BitInteger.
- // dst: mantissa[51:20].
- // scratch2: 1
-
- // Shift back the higher bits of the mantissa.
- __ srlv(dst, dst, scratch3);
- // Set the implicit first bit.
- __ li(at, 32);
- __ subu(scratch3, at, scratch3);
- __ sllv(scratch2, scratch2, scratch3);
- __ Or(dst, dst, scratch2);
- // Set the sign.
- __ lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
- Label skip_sub;
- __ Branch(&skip_sub, ge, scratch1, Operand(zero_reg));
- __ Subu(dst, zero_reg, dst);
- __ bind(&skip_sub);
- }
+ // Jump to not_int32 if the operation did not succeed.
+ __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
__ Branch(&done);
__ bind(&maybe_undefined);
@@ -1032,66 +747,6 @@
}
-void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
- Register src_exponent,
- Register src_mantissa,
- Register dst,
- Register scratch,
- Label* not_int32) {
- // Get exponent alone in scratch.
- __ Ext(scratch,
- src_exponent,
- HeapNumber::kExponentShift,
- HeapNumber::kExponentBits);
-
- // Substract the bias from the exponent.
- __ Subu(scratch, scratch, Operand(HeapNumber::kExponentBias));
-
- // src1: higher (exponent) part of the double value.
- // src2: lower (mantissa) part of the double value.
- // scratch: unbiased exponent.
-
- // Fast cases. Check for obvious non 32-bit integer values.
- // Negative exponent cannot yield 32-bit integers.
- __ Branch(not_int32, lt, scratch, Operand(zero_reg));
- // Exponent greater than 31 cannot yield 32-bit integers.
- // Also, a positive value with an exponent equal to 31 is outside of the
- // signed 32-bit integer range.
- // Another way to put it is that if (exponent - signbit) > 30 then the
- // number cannot be represented as an int32.
- Register tmp = dst;
- __ srl(at, src_exponent, 31);
- __ subu(tmp, scratch, at);
- __ Branch(not_int32, gt, tmp, Operand(30));
- // - Bits [21:0] in the mantissa are not null.
- __ And(tmp, src_mantissa, 0x3fffff);
- __ Branch(not_int32, ne, tmp, Operand(zero_reg));
-
- // Otherwise the exponent needs to be big enough to shift left all the
- // non zero bits left. So we need the (30 - exponent) last bits of the
- // 31 higher bits of the mantissa to be null.
- // Because bits [21:0] are null, we can check instead that the
- // (32 - exponent) last bits of the 32 higher bits of the mantissa are null.
-
- // Get the 32 higher bits of the mantissa in dst.
- __ Ext(dst,
- src_mantissa,
- HeapNumber::kMantissaBitsInTopWord,
- 32 - HeapNumber::kMantissaBitsInTopWord);
- __ sll(at, src_exponent, HeapNumber::kNonMantissaBitsInTopWord);
- __ or_(dst, dst, at);
-
- // Create the mask and test the lower bits (of the higher bits).
- __ li(at, 32);
- __ subu(scratch, at, scratch);
- __ li(src_mantissa, 1);
- __ sllv(src_exponent, src_mantissa, scratch);
- __ Subu(src_exponent, src_exponent, Operand(1));
- __ And(src_exponent, dst, src_exponent);
- __ Branch(not_int32, ne, src_exponent, Operand(zero_reg));
-}
-
-
void FloatingPointHelper::CallCCodeForDoubleOperation(
MacroAssembler* masm,
Token::Value op,
@@ -1111,7 +766,6 @@
__ push(ra);
__ PrepareCallCFunction(4, scratch); // Two doubles are 4 arguments.
if (!IsMipsSoftFloatABI) {
- CpuFeatureScope scope(masm, FPU);
// We are not using MIPS FPU instructions, and parameters for the runtime
// function call are prepaired in a0-a3 registers, but function we are
// calling is compiled with hard-float flag and expecting hard float ABI
@@ -1127,7 +781,6 @@
}
// Store answer in the overwritable heap number.
if (!IsMipsSoftFloatABI) {
- CpuFeatureScope scope(masm, FPU);
// Double returned in register f0.
__ sdc1(f0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
} else {
@@ -1350,25 +1003,10 @@
// Rhs is a smi, lhs is a number.
// Convert smi rhs to double.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ sra(at, rhs, kSmiTagSize);
- __ mtc1(at, f14);
- __ cvt_d_w(f14, f14);
- __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
- } else {
- // Load lhs to a double in a2, a3.
- __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
- __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-
- // Write Smi from rhs to a1 and a0 in double format. t5 is scratch.
- __ mov(t6, rhs);
- ConvertToDoubleStub stub1(a1, a0, t6, t5);
- __ push(ra);
- __ Call(stub1.GetCode(masm->isolate()));
-
- __ pop(ra);
- }
+ __ sra(at, rhs, kSmiTagSize);
+ __ mtc1(at, f14);
+ __ cvt_d_w(f14, f14);
+ __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
// We now have both loaded as doubles.
__ jmp(both_loaded_as_doubles);
@@ -1389,179 +1027,14 @@
// Lhs is a smi, rhs is a number.
// Convert smi lhs to double.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ sra(at, lhs, kSmiTagSize);
- __ mtc1(at, f12);
- __ cvt_d_w(f12, f12);
- __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- } else {
- // Convert lhs to a double format. t5 is scratch.
- __ mov(t6, lhs);
- ConvertToDoubleStub stub2(a3, a2, t6, t5);
- __ push(ra);
- __ Call(stub2.GetCode(masm->isolate()));
- __ pop(ra);
- // Load rhs to a double in a1, a0.
- if (rhs.is(a0)) {
- __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
- __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- } else {
- __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
- }
- }
+ __ sra(at, lhs, kSmiTagSize);
+ __ mtc1(at, f12);
+ __ cvt_d_w(f12, f12);
+ __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
// Fall through to both_loaded_as_doubles.
}
-void EmitNanCheck(MacroAssembler* masm, Condition cc) {
- bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Lhs and rhs are already loaded to f12 and f14 register pairs.
- __ Move(t0, t1, f14);
- __ Move(t2, t3, f12);
- } else {
- // Lhs and rhs are already loaded to GP registers.
- __ mov(t0, a0); // a0 has LS 32 bits of rhs.
- __ mov(t1, a1); // a1 has MS 32 bits of rhs.
- __ mov(t2, a2); // a2 has LS 32 bits of lhs.
- __ mov(t3, a3); // a3 has MS 32 bits of lhs.
- }
- Register rhs_exponent = exp_first ? t0 : t1;
- Register lhs_exponent = exp_first ? t2 : t3;
- Register rhs_mantissa = exp_first ? t1 : t0;
- Register lhs_mantissa = exp_first ? t3 : t2;
- Label one_is_nan, neither_is_nan;
- Label lhs_not_nan_exp_mask_is_loaded;
-
- Register exp_mask_reg = t4;
- __ li(exp_mask_reg, HeapNumber::kExponentMask);
- __ and_(t5, lhs_exponent, exp_mask_reg);
- __ Branch(&lhs_not_nan_exp_mask_is_loaded, ne, t5, Operand(exp_mask_reg));
-
- __ sll(t5, lhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
- __ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
-
- __ Branch(&one_is_nan, ne, lhs_mantissa, Operand(zero_reg));
-
- __ li(exp_mask_reg, HeapNumber::kExponentMask);
- __ bind(&lhs_not_nan_exp_mask_is_loaded);
- __ and_(t5, rhs_exponent, exp_mask_reg);
-
- __ Branch(&neither_is_nan, ne, t5, Operand(exp_mask_reg));
-
- __ sll(t5, rhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
- __ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
-
- __ Branch(&neither_is_nan, eq, rhs_mantissa, Operand(zero_reg));
-
- __ bind(&one_is_nan);
- // NaN comparisons always fail.
- // Load whatever we need in v0 to make the comparison fail.
-
- if (cc == lt || cc == le) {
- __ li(v0, Operand(GREATER));
- } else {
- __ li(v0, Operand(LESS));
- }
- __ Ret();
-
- __ bind(&neither_is_nan);
-}
-
-
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
- // f12 and f14 have the two doubles. Neither is a NaN.
- // Call a native function to do a comparison between two non-NaNs.
- // Call C routine that may not cause GC or other trouble.
- // We use a call_was and return manually because we need arguments slots to
- // be freed.
-
- Label return_result_not_equal, return_result_equal;
- if (cc == eq) {
- // Doubles are not equal unless they have the same bit pattern.
- // Exception: 0 and -0.
- bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Lhs and rhs are already loaded to f12 and f14 register pairs.
- __ Move(t0, t1, f14);
- __ Move(t2, t3, f12);
- } else {
- // Lhs and rhs are already loaded to GP registers.
- __ mov(t0, a0); // a0 has LS 32 bits of rhs.
- __ mov(t1, a1); // a1 has MS 32 bits of rhs.
- __ mov(t2, a2); // a2 has LS 32 bits of lhs.
- __ mov(t3, a3); // a3 has MS 32 bits of lhs.
- }
- Register rhs_exponent = exp_first ? t0 : t1;
- Register lhs_exponent = exp_first ? t2 : t3;
- Register rhs_mantissa = exp_first ? t1 : t0;
- Register lhs_mantissa = exp_first ? t3 : t2;
-
- __ xor_(v0, rhs_mantissa, lhs_mantissa);
- __ Branch(&return_result_not_equal, ne, v0, Operand(zero_reg));
-
- __ subu(v0, rhs_exponent, lhs_exponent);
- __ Branch(&return_result_equal, eq, v0, Operand(zero_reg));
- // 0, -0 case.
- __ sll(rhs_exponent, rhs_exponent, kSmiTagSize);
- __ sll(lhs_exponent, lhs_exponent, kSmiTagSize);
- __ or_(t4, rhs_exponent, lhs_exponent);
- __ or_(t4, t4, rhs_mantissa);
-
- __ Branch(&return_result_not_equal, ne, t4, Operand(zero_reg));
-
- __ bind(&return_result_equal);
-
- __ li(v0, Operand(EQUAL));
- __ Ret();
- }
-
- __ bind(&return_result_not_equal);
-
- if (!CpuFeatures::IsSupported(FPU)) {
- __ push(ra);
- __ PrepareCallCFunction(0, 2, t4);
- if (!IsMipsSoftFloatABI) {
- // We are not using MIPS FPU instructions, and parameters for the runtime
- // function call are prepaired in a0-a3 registers, but function we are
- // calling is compiled with hard-float flag and expecting hard float ABI
- // (parameters in f12/f14 registers). We need to copy parameters from
- // a0-a3 registers to f12/f14 register pairs.
- __ Move(f12, a0, a1);
- __ Move(f14, a2, a3);
- }
-
- AllowExternalCallThatCantCauseGC scope(masm);
- __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
- 0, 2);
- __ pop(ra); // Because this function returns int, result is in v0.
- __ Ret();
- } else {
- CpuFeatureScope scope(masm, FPU);
- Label equal, less_than;
- __ BranchF(&equal, NULL, eq, f12, f14);
- __ BranchF(&less_than, NULL, lt, f12, f14);
-
- // Not equal, not less, not NaN, must be greater.
-
- __ li(v0, Operand(GREATER));
- __ Ret();
-
- __ bind(&equal);
- __ li(v0, Operand(EQUAL));
- __ Ret();
-
- __ bind(&less_than);
- __ li(v0, Operand(LESS));
- __ Ret();
- }
-}
-
-
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
Register lhs,
Register rhs) {
@@ -1616,21 +1089,9 @@
// Both are heap numbers. Load them up then jump to the code we have
// for that.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
- __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- } else {
- __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
- __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
- if (rhs.is(a0)) {
- __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
- __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- } else {
- __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
- __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
- }
- }
+ __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
+ __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
+
__ jmp(both_loaded_as_doubles);
}
@@ -1711,42 +1172,34 @@
Label load_result_from_cache;
if (!object_is_smi) {
__ JumpIfSmi(object, &is_smi);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ CheckMap(object,
- scratch1,
- Heap::kHeapNumberMapRootIndex,
- not_found,
- DONT_DO_SMI_CHECK);
+ __ CheckMap(object,
+ scratch1,
+ Heap::kHeapNumberMapRootIndex,
+ not_found,
+ DONT_DO_SMI_CHECK);
- STATIC_ASSERT(8 == kDoubleSize);
- __ Addu(scratch1,
- object,
- Operand(HeapNumber::kValueOffset - kHeapObjectTag));
- __ lw(scratch2, MemOperand(scratch1, kPointerSize));
- __ lw(scratch1, MemOperand(scratch1, 0));
- __ Xor(scratch1, scratch1, Operand(scratch2));
- __ And(scratch1, scratch1, Operand(mask));
+ STATIC_ASSERT(8 == kDoubleSize);
+ __ Addu(scratch1,
+ object,
+ Operand(HeapNumber::kValueOffset - kHeapObjectTag));
+ __ lw(scratch2, MemOperand(scratch1, kPointerSize));
+ __ lw(scratch1, MemOperand(scratch1, 0));
+ __ Xor(scratch1, scratch1, Operand(scratch2));
+ __ And(scratch1, scratch1, Operand(mask));
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- __ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
- __ Addu(scratch1, number_string_cache, scratch1);
+ // Calculate address of entry in string cache: each entry consists
+ // of two pointer sized fields.
+ __ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
+ __ Addu(scratch1, number_string_cache, scratch1);
- Register probe = mask;
- __ lw(probe,
- FieldMemOperand(scratch1, FixedArray::kHeaderSize));
- __ JumpIfSmi(probe, not_found);
- __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
- __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
- __ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
- __ Branch(not_found);
- } else {
- // Note that there is no cache check for non-FPU case, even though
- // it seems there could be. May be a tiny opimization for non-FPU
- // cores.
- __ Branch(not_found);
- }
+ Register probe = mask;
+ __ lw(probe,
+ FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+ __ JumpIfSmi(probe, not_found);
+ __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
+ __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
+ __ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
+ __ Branch(not_found);
}
__ bind(&is_smi);
@@ -1864,49 +1317,38 @@
// left hand side and a0, a1 represent right hand side.
Isolate* isolate = masm->isolate();
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- Label nan;
- __ li(t0, Operand(LESS));
- __ li(t1, Operand(GREATER));
- __ li(t2, Operand(EQUAL));
+ Label nan;
+ __ li(t0, Operand(LESS));
+ __ li(t1, Operand(GREATER));
+ __ li(t2, Operand(EQUAL));
- // Check if either rhs or lhs is NaN.
- __ BranchF(NULL, &nan, eq, f12, f14);
+ // Check if either rhs or lhs is NaN.
+ __ BranchF(NULL, &nan, eq, f12, f14);
- // Check if LESS condition is satisfied. If true, move conditionally
- // result to v0.
- __ c(OLT, D, f12, f14);
- __ Movt(v0, t0);
- // Use previous check to store conditionally to v0 oposite condition
- // (GREATER). If rhs is equal to lhs, this will be corrected in next
- // check.
- __ Movf(v0, t1);
- // Check if EQUAL condition is satisfied. If true, move conditionally
- // result to v0.
- __ c(EQ, D, f12, f14);
- __ Movt(v0, t2);
+ // Check if LESS condition is satisfied. If true, move conditionally
+ // result to v0.
+ __ c(OLT, D, f12, f14);
+ __ Movt(v0, t0);
+ // Use previous check to store conditionally to v0 oposite condition
+ // (GREATER). If rhs is equal to lhs, this will be corrected in next
+ // check.
+ __ Movf(v0, t1);
+ // Check if EQUAL condition is satisfied. If true, move conditionally
+ // result to v0.
+ __ c(EQ, D, f12, f14);
+ __ Movt(v0, t2);
- __ Ret();
+ __ Ret();
- __ bind(&nan);
- // NaN comparisons always fail.
- // Load whatever we need in v0 to make the comparison fail.
- if (cc == lt || cc == le) {
- __ li(v0, Operand(GREATER));
- } else {
- __ li(v0, Operand(LESS));
- }
- __ Ret();
+ __ bind(&nan);
+ // NaN comparisons always fail.
+ // Load whatever we need in v0 to make the comparison fail.
+ if (cc == lt || cc == le) {
+ __ li(v0, Operand(GREATER));
} else {
- // Checks for NaN in the doubles we have loaded. Can return the answer or
- // fall through if neither is a NaN. Also binds rhs_not_nan.
- EmitNanCheck(masm, cc);
-
- // Compares two doubles that are not NaNs. Returns the answer.
- // Never falls through.
- EmitTwoNonNanDoubleComparison(masm, cc);
+ __ li(v0, Operand(LESS));
}
+ __ Ret();
__ bind(¬_smis);
// At this point we know we are dealing with two different objects,
@@ -1999,9 +1441,6 @@
// The stub expects its argument in the tos_ register and returns its result in
// it, too: zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
- // This stub uses FPU instructions.
- CpuFeatureScope scope(masm, FPU);
-
Label patch;
const Register map = t5.is(tos_) ? t3 : t5;
@@ -2115,7 +1554,6 @@
// restore them.
__ MultiPush(kJSCallerSaved | ra.bit());
if (save_doubles_ == kSaveFPRegs) {
- CpuFeatureScope scope(masm, FPU);
__ MultiPushFPU(kCallerSavedFPU);
}
const int argument_count = 1;
@@ -2129,7 +1567,6 @@
ExternalReference::store_buffer_overflow_function(masm->isolate()),
argument_count);
if (save_doubles_ == kSaveFPRegs) {
- CpuFeatureScope scope(masm, FPU);
__ MultiPopFPU(kCallerSavedFPU);
}
@@ -2360,19 +1797,11 @@
__ mov(v0, a2); // Move newly allocated heap number to v0.
}
- if (CpuFeatures::IsSupported(FPU)) {
- // Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
- CpuFeatureScope scope(masm, FPU);
- __ mtc1(a1, f0);
- __ cvt_d_w(f0, f0);
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
- __ Ret();
- } else {
- // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
- // have to set up a frame.
- WriteInt32ToHeapNumberStub stub(a1, v0, a2, a3);
- __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
- }
+ // Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
+ __ mtc1(a1, f0);
+ __ cvt_d_w(f0, f0);
+ __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ Ret();
__ bind(&impossible);
if (FLAG_debug_code) {
@@ -2434,7 +1863,7 @@
void BinaryOpStub::Initialize() {
- platform_specific_bit_ = CpuFeatures::IsSupported(FPU);
+ platform_specific_bit_ = true; // FPU is a base requirement for V8.
}
@@ -2661,9 +2090,8 @@
case Token::DIV:
case Token::MOD: {
// Load left and right operands into f12 and f14 or a0/a1 and a2/a3
- // depending on whether FPU is available or not.
+ // depending on operation.
FloatingPointHelper::Destination destination =
- CpuFeatures::IsSupported(FPU) &&
op != Token::MOD ?
FloatingPointHelper::kFPURegisters :
FloatingPointHelper::kCoreRegisters;
@@ -2688,20 +2116,16 @@
masm, destination, right, f14, a2, a3, heap_number_map,
scratch1, scratch2, fail);
}
- // Use scratch3 as left in LoadNumber functions to avoid overwriting of
- // left (a0) register.
- __ mov(scratch3, left);
-
// Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it
// jumps to |miss|.
if (left_type == BinaryOpIC::INT32) {
FloatingPointHelper::LoadNumberAsInt32Double(
- masm, scratch3, destination, f12, f16, a0, a1, heap_number_map,
+ masm, left, destination, f12, f16, a0, a1, heap_number_map,
scratch1, scratch2, f2, miss);
} else {
Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
FloatingPointHelper::LoadNumber(
- masm, destination, scratch3, f12, a0, a1, heap_number_map,
+ masm, destination, left, f12, a0, a1, heap_number_map,
scratch1, scratch2, fail);
}
}
@@ -2711,7 +2135,6 @@
// Using FPU registers:
// f12: Left value.
// f14: Right value.
- CpuFeatureScope scope(masm, FPU);
switch (op) {
case Token::ADD:
__ add_d(f10, f12, f14);
@@ -2801,11 +2224,7 @@
// The code below for writing into heap numbers isn't capable of
// writing the register as an unsigned int so we go to slow case if we
// hit this case.
- if (CpuFeatures::IsSupported(FPU)) {
- __ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
- } else {
- __ Branch(not_numbers, lt, a2, Operand(zero_reg));
- }
+ __ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
break;
case Token::SHL:
// Use only the 5 least significant bits of the shift count.
@@ -2839,28 +2258,19 @@
// Nothing can go wrong now, so move the heap number to v0, which is the
// result.
__ mov(v0, t1);
-
- if (CpuFeatures::IsSupported(FPU)) {
- // Convert the int32 in a2 to the heap number in a0. As
- // mentioned above SHR needs to always produce a positive result.
- CpuFeatureScope scope(masm, FPU);
- __ mtc1(a2, f0);
- if (op == Token::SHR) {
- __ Cvt_d_uw(f0, f0, f22);
- } else {
- __ cvt_d_w(f0, f0);
- }
- // ARM uses a workaround here because of the unaligned HeapNumber
- // kValueOffset. On MIPS this workaround is built into sdc1 so
- // there's no point in generating even more instructions.
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
- __ Ret();
+ // Convert the int32 in a2 to the heap number in a0. As
+ // mentioned above SHR needs to always produce a positive result.
+ __ mtc1(a2, f0);
+ if (op == Token::SHR) {
+ __ Cvt_d_uw(f0, f0, f22);
} else {
- // Tail call that writes the int32 in a2 to the heap number in v0, using
- // a3 and a0 as scratch. v0 is preserved and returned.
- WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
- __ TailCallStub(&stub);
+ __ cvt_d_w(f0, f0);
}
+ // ARM uses a workaround here because of the unaligned HeapNumber
+ // kValueOffset. On MIPS this workaround is built into sdc1 so
+ // there's no point in generating even more instructions.
+ __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ Ret();
break;
}
default:
@@ -3007,8 +2417,7 @@
// Load both operands and check that they are 32-bit integer.
// Jump to type transition if they are not. The registers a0 and a1 (right
// and left) are preserved for the runtime call.
- FloatingPointHelper::Destination destination =
- (CpuFeatures::IsSupported(FPU) && op_ != Token::MOD)
+ FloatingPointHelper::Destination destination = (op_ != Token::MOD)
? FloatingPointHelper::kFPURegisters
: FloatingPointHelper::kCoreRegisters;
@@ -3038,7 +2447,6 @@
&transition);
if (destination == FloatingPointHelper::kFPURegisters) {
- CpuFeatureScope scope(masm, FPU);
Label return_heap_number;
switch (op_) {
case Token::ADD:
@@ -3207,23 +2615,12 @@
// We only get a negative result if the shift value (a2) is 0.
// This result cannot be respresented as a signed 32-bit integer, try
// to return a heap number if we can.
- // The non FPU code does not support this special case, so jump to
- // runtime if we don't support it.
- if (CpuFeatures::IsSupported(FPU)) {
- __ Branch((result_type_ <= BinaryOpIC::INT32)
- ? &transition
- : &return_heap_number,
- lt,
- a2,
- Operand(zero_reg));
- } else {
- __ Branch((result_type_ <= BinaryOpIC::INT32)
- ? &transition
- : &call_runtime,
- lt,
- a2,
- Operand(zero_reg));
- }
+ __ Branch((result_type_ <= BinaryOpIC::INT32)
+ ? &transition
+ : &return_heap_number,
+ lt,
+ a2,
+ Operand(zero_reg));
break;
case Token::SHL:
__ And(a2, a2, Operand(0x1f));
@@ -3251,31 +2648,21 @@
&call_runtime,
mode_);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
-
- if (op_ != Token::SHR) {
- // Convert the result to a floating point value.
- __ mtc1(a2, double_scratch);
- __ cvt_d_w(double_scratch, double_scratch);
- } else {
- // The result must be interpreted as an unsigned 32-bit integer.
- __ mtc1(a2, double_scratch);
- __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
- }
-
- // Store the result.
- __ mov(v0, heap_number_result);
- __ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
- __ Ret();
+ if (op_ != Token::SHR) {
+ // Convert the result to a floating point value.
+ __ mtc1(a2, double_scratch);
+ __ cvt_d_w(double_scratch, double_scratch);
} else {
- // Tail call that writes the int32 in a2 to the heap number in v0, using
- // a3 and a0 as scratch. v0 is preserved and returned.
- __ mov(v0, t1);
- WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
- __ TailCallStub(&stub);
+ // The result must be interpreted as an unsigned 32-bit integer.
+ __ mtc1(a2, double_scratch);
+ __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
}
+ // Store the result.
+ __ mov(v0, heap_number_result);
+ __ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ Ret();
+
break;
}
@@ -3455,107 +2842,102 @@
const Register cache_entry = a0;
const bool tagged = (argument_type_ == TAGGED);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
+ if (tagged) {
+ // Argument is a number and is on stack and in a0.
+ // Load argument and check if it is a smi.
+ __ JumpIfNotSmi(a0, &input_not_smi);
- if (tagged) {
- // Argument is a number and is on stack and in a0.
- // Load argument and check if it is a smi.
- __ JumpIfNotSmi(a0, &input_not_smi);
+ // Input is a smi. Convert to double and load the low and high words
+ // of the double into a2, a3.
+ __ sra(t0, a0, kSmiTagSize);
+ __ mtc1(t0, f4);
+ __ cvt_d_w(f4, f4);
+ __ Move(a2, a3, f4);
+ __ Branch(&loaded);
- // Input is a smi. Convert to double and load the low and high words
- // of the double into a2, a3.
- __ sra(t0, a0, kSmiTagSize);
- __ mtc1(t0, f4);
- __ cvt_d_w(f4, f4);
- __ Move(a2, a3, f4);
- __ Branch(&loaded);
+ __ bind(&input_not_smi);
+ // Check if input is a HeapNumber.
+ __ CheckMap(a0,
+ a1,
+ Heap::kHeapNumberMapRootIndex,
+ &calculate,
+ DONT_DO_SMI_CHECK);
+ // Input is a HeapNumber. Store the
+ // low and high words into a2, a3.
+ __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
+ __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
+ } else {
+ // Input is untagged double in f4. Output goes to f4.
+ __ Move(a2, a3, f4);
+ }
+ __ bind(&loaded);
+ // a2 = low 32 bits of double value.
+ // a3 = high 32 bits of double value.
+ // Compute hash (the shifts are arithmetic):
+ // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
+ __ Xor(a1, a2, a3);
+ __ sra(t0, a1, 16);
+ __ Xor(a1, a1, t0);
+ __ sra(t0, a1, 8);
+ __ Xor(a1, a1, t0);
+ ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+ __ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
- __ bind(&input_not_smi);
- // Check if input is a HeapNumber.
- __ CheckMap(a0,
- a1,
- Heap::kHeapNumberMapRootIndex,
- &calculate,
- DONT_DO_SMI_CHECK);
- // Input is a HeapNumber. Store the
- // low and high words into a2, a3.
- __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
- __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
- } else {
- // Input is untagged double in f4. Output goes to f4.
- __ Move(a2, a3, f4);
- }
- __ bind(&loaded);
- // a2 = low 32 bits of double value.
- // a3 = high 32 bits of double value.
- // Compute hash (the shifts are arithmetic):
- // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
- __ Xor(a1, a2, a3);
- __ sra(t0, a1, 16);
- __ Xor(a1, a1, t0);
- __ sra(t0, a1, 8);
- __ Xor(a1, a1, t0);
- ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
- __ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
-
- // a2 = low 32 bits of double value.
- // a3 = high 32 bits of double value.
- // a1 = TranscendentalCache::hash(double value).
- __ li(cache_entry, Operand(
- ExternalReference::transcendental_cache_array_address(
- masm->isolate())));
- // a0 points to cache array.
- __ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
- Isolate::Current()->transcendental_cache()->caches_[0])));
- // a0 points to the cache for the type type_.
- // If NULL, the cache hasn't been initialized yet, so go through runtime.
- __ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
+ // a2 = low 32 bits of double value.
+ // a3 = high 32 bits of double value.
+ // a1 = TranscendentalCache::hash(double value).
+ __ li(cache_entry, Operand(
+ ExternalReference::transcendental_cache_array_address(
+ masm->isolate())));
+ // a0 points to cache array.
+ __ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
+ Isolate::Current()->transcendental_cache()->caches_[0])));
+ // a0 points to the cache for the type type_.
+ // If NULL, the cache hasn't been initialized yet, so go through runtime.
+ __ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
#ifdef DEBUG
- // Check that the layout of cache elements match expectations.
- { TranscendentalCache::SubCache::Element test_elem[2];
- char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
- char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
- char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
- char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
- char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
- CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
- CHECK_EQ(0, elem_in0 - elem_start);
- CHECK_EQ(kIntSize, elem_in1 - elem_start);
- CHECK_EQ(2 * kIntSize, elem_out - elem_start);
- }
+ // Check that the layout of cache elements match expectations.
+ { TranscendentalCache::SubCache::Element test_elem[2];
+ char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
+ char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
+ char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
+ char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
+ char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
+ CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
+ CHECK_EQ(0, elem_in0 - elem_start);
+ CHECK_EQ(kIntSize, elem_in1 - elem_start);
+ CHECK_EQ(2 * kIntSize, elem_out - elem_start);
+ }
#endif
- // Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
- __ sll(t0, a1, 1);
- __ Addu(a1, a1, t0);
- __ sll(t0, a1, 2);
- __ Addu(cache_entry, cache_entry, t0);
+ // Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
+ __ sll(t0, a1, 1);
+ __ Addu(a1, a1, t0);
+ __ sll(t0, a1, 2);
+ __ Addu(cache_entry, cache_entry, t0);
- // Check if cache matches: Double value is stored in uint32_t[2] array.
- __ lw(t0, MemOperand(cache_entry, 0));
- __ lw(t1, MemOperand(cache_entry, 4));
- __ lw(t2, MemOperand(cache_entry, 8));
- __ Branch(&calculate, ne, a2, Operand(t0));
- __ Branch(&calculate, ne, a3, Operand(t1));
- // Cache hit. Load result, cleanup and return.
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(
- counters->transcendental_cache_hit(), 1, scratch0, scratch1);
- if (tagged) {
- // Pop input value from stack and load result into v0.
- __ Drop(1);
- __ mov(v0, t2);
- } else {
- // Load result into f4.
- __ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
- }
- __ Ret();
- } // if (CpuFeatures::IsSupported(FPU))
+ // Check if cache matches: Double value is stored in uint32_t[2] array.
+ __ lw(t0, MemOperand(cache_entry, 0));
+ __ lw(t1, MemOperand(cache_entry, 4));
+ __ lw(t2, MemOperand(cache_entry, 8));
+ __ Branch(&calculate, ne, a2, Operand(t0));
+ __ Branch(&calculate, ne, a3, Operand(t1));
+ // Cache hit. Load result, cleanup and return.
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(
+ counters->transcendental_cache_hit(), 1, scratch0, scratch1);
+ if (tagged) {
+ // Pop input value from stack and load result into v0.
+ __ Drop(1);
+ __ mov(v0, t2);
+ } else {
+ // Load result into f4.
+ __ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
+ }
+ __ Ret();
__ bind(&calculate);
- Counters* counters = masm->isolate()->counters();
__ IncrementCounter(
counters->transcendental_cache_miss(), 1, scratch0, scratch1);
if (tagged) {
@@ -3565,9 +2947,6 @@
1,
1);
} else {
- ASSERT(CpuFeatures::IsSupported(FPU));
- CpuFeatureScope scope(masm, FPU);
-
Label no_update;
Label skip_cache;
@@ -3694,7 +3073,6 @@
void MathPowStub::Generate(MacroAssembler* masm) {
- CpuFeatureScope fpu_scope(masm, FPU);
const Register base = a1;
const Register exponent = a2;
const Register heapnumbermap = t1;
@@ -3924,14 +3302,13 @@
CEntryStub::GenerateAheadOfTime(isolate);
WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+ StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
}
void CodeStub::GenerateFPStubs(Isolate* isolate) {
- SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
- ? kSaveFPRegs
- : kDontSaveFPRegs;
+ SaveFPRegsMode mode = kSaveFPRegs;
CEntryStub save_doubles(1, mode);
StoreBufferOverflowStub stub(mode);
// These stubs might already be in the snapshot, detect that and don't
@@ -3940,11 +3317,13 @@
Code* save_doubles_code;
if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
save_doubles_code = *save_doubles.GetCode(isolate);
- save_doubles_code->set_is_pregenerated(true);
-
- Code* store_buffer_overflow_code = *stub.GetCode(isolate);
- store_buffer_overflow_code->set_is_pregenerated(true);
}
+ Code* store_buffer_overflow_code;
+ if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
+ store_buffer_overflow_code = *stub.GetCode(isolate);
+ }
+ save_doubles_code->set_is_pregenerated(true);
+ store_buffer_overflow_code->set_is_pregenerated(true);
isolate->set_fp_stubs_generated(true);
}
@@ -4075,11 +3454,18 @@
// Special handling of out of memory exceptions.
JumpIfOOM(masm, v0, t0, throw_out_of_memory_exception);
- // Retrieve the pending exception and clear the variable.
- __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
+ // Retrieve the pending exception.
__ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ lw(v0, MemOperand(t0));
+
+ // See if we just retrieved an OOM exception.
+ JumpIfOOM(masm, v0, t0, throw_out_of_memory_exception);
+
+ // Clear the pending exception.
+ __ li(a3, Operand(isolate->factory()->the_hole_value()));
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+ isolate)));
__ sw(a3, MemOperand(t0));
// Special handling of termination exceptions which are uncatchable
@@ -4200,20 +3586,15 @@
// Save callee saved registers on the stack.
__ MultiPush(kCalleeSaved | ra.bit());
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Save callee-saved FPU registers.
- __ MultiPushFPU(kCalleeSavedFPU);
- // Set up the reserved register for 0.0.
- __ Move(kDoubleRegZero, 0.0);
- }
+ // Save callee-saved FPU registers.
+ __ MultiPushFPU(kCalleeSavedFPU);
+ // Set up the reserved register for 0.0.
+ __ Move(kDoubleRegZero, 0.0);
// Load argv in s0 register.
int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
- if (CpuFeatures::IsSupported(FPU)) {
- offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
- }
+ offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
__ InitializeRootRegister();
__ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
@@ -4349,11 +3730,8 @@
// Reset the stack to the callee saved registers.
__ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- // Restore callee-saved fpu registers.
- __ MultiPopFPU(kCalleeSavedFPU);
- }
+ // Restore callee-saved fpu registers.
+ __ MultiPopFPU(kCalleeSavedFPU);
// Restore callee saved registers from the stack.
__ MultiPop(kCalleeSaved | ra.bit());
@@ -7092,59 +6470,55 @@
}
// Inlining the double comparison and falling back to the general compare
- // stub if NaN is involved or FPU is unsupported.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
+ // stub if NaN is involved.
+ // Load left and right operand.
+ Label done, left, left_smi, right_smi;
+ __ JumpIfSmi(a0, &right_smi);
+ __ CheckMap(a0, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
+ DONT_DO_SMI_CHECK);
+ __ Subu(a2, a0, Operand(kHeapObjectTag));
+ __ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset));
+ __ Branch(&left);
+ __ bind(&right_smi);
+ __ SmiUntag(a2, a0); // Can't clobber a0 yet.
+ FPURegister single_scratch = f6;
+ __ mtc1(a2, single_scratch);
+ __ cvt_d_w(f2, single_scratch);
- // Load left and right operand.
- Label done, left, left_smi, right_smi;
- __ JumpIfSmi(a0, &right_smi);
- __ CheckMap(a0, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
- DONT_DO_SMI_CHECK);
- __ Subu(a2, a0, Operand(kHeapObjectTag));
- __ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset));
- __ Branch(&left);
- __ bind(&right_smi);
- __ SmiUntag(a2, a0); // Can't clobber a0 yet.
- FPURegister single_scratch = f6;
- __ mtc1(a2, single_scratch);
- __ cvt_d_w(f2, single_scratch);
+ __ bind(&left);
+ __ JumpIfSmi(a1, &left_smi);
+ __ CheckMap(a1, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
+ DONT_DO_SMI_CHECK);
+ __ Subu(a2, a1, Operand(kHeapObjectTag));
+ __ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset));
+ __ Branch(&done);
+ __ bind(&left_smi);
+ __ SmiUntag(a2, a1); // Can't clobber a1 yet.
+ single_scratch = f8;
+ __ mtc1(a2, single_scratch);
+ __ cvt_d_w(f0, single_scratch);
- __ bind(&left);
- __ JumpIfSmi(a1, &left_smi);
- __ CheckMap(a1, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
- DONT_DO_SMI_CHECK);
- __ Subu(a2, a1, Operand(kHeapObjectTag));
- __ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset));
- __ Branch(&done);
- __ bind(&left_smi);
- __ SmiUntag(a2, a1); // Can't clobber a1 yet.
- single_scratch = f8;
- __ mtc1(a2, single_scratch);
- __ cvt_d_w(f0, single_scratch);
+ __ bind(&done);
- __ bind(&done);
+ // Return a result of -1, 0, or 1, or use CompareStub for NaNs.
+ Label fpu_eq, fpu_lt;
+ // Test if equal, and also handle the unordered/NaN case.
+ __ BranchF(&fpu_eq, &unordered, eq, f0, f2);
- // Return a result of -1, 0, or 1, or use CompareStub for NaNs.
- Label fpu_eq, fpu_lt;
- // Test if equal, and also handle the unordered/NaN case.
- __ BranchF(&fpu_eq, &unordered, eq, f0, f2);
+ // Test if less (unordered case is already handled).
+ __ BranchF(&fpu_lt, NULL, lt, f0, f2);
- // Test if less (unordered case is already handled).
- __ BranchF(&fpu_lt, NULL, lt, f0, f2);
+ // Otherwise it's greater, so just fall thru, and return.
+ __ li(v0, Operand(GREATER));
+ __ Ret();
- // Otherwise it's greater, so just fall thru, and return.
- __ li(v0, Operand(GREATER));
- __ Ret();
+ __ bind(&fpu_eq);
+ __ li(v0, Operand(EQUAL));
+ __ Ret();
- __ bind(&fpu_eq);
- __ li(v0, Operand(EQUAL));
- __ Ret();
-
- __ bind(&fpu_lt);
- __ li(v0, Operand(LESS));
- __ Ret();
- }
+ __ bind(&fpu_lt);
+ __ li(v0, Operand(LESS));
+ __ Ret();
__ bind(&unordered);
__ bind(&generic_stub);
@@ -7785,11 +7159,6 @@
}
-bool StoreBufferOverflowStub::IsPregenerated() {
- return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated();
-}
-
-
void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
Isolate* isolate) {
StoreBufferOverflowStub stub1(kDontSaveFPRegs);
@@ -7812,7 +7181,7 @@
bool CodeStub::CanUseFPRegisters() {
- return CpuFeatures::IsSupported(FPU);
+ return true; // FPU is a base requirement for V8.
}
@@ -8080,9 +7449,7 @@
void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
- ASSERT(!Serializer::enabled());
- bool save_fp_regs = CpuFeatures::IsSupported(FPU);
- CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
+ CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
__ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index 225accc..0ebfe59 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -62,11 +62,11 @@
class StoreBufferOverflowStub: public PlatformCodeStub {
public:
explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
- : save_doubles_(save_fp) { }
+ : save_doubles_(save_fp) {}
void Generate(MacroAssembler* masm);
- virtual bool IsPregenerated();
+ virtual bool IsPregenerated() { return true; }
static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
virtual bool SometimesSetsUpAFrame() { return false; }
@@ -484,7 +484,6 @@
void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
if (mode == kSaveFPRegs) {
- CpuFeatureScope scope(masm, FPU);
masm->MultiPushFPU(kCallerSavedFPU);
}
}
@@ -492,7 +491,6 @@
inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
SaveFPRegsMode mode) {
if (mode == kSaveFPRegs) {
- CpuFeatureScope scope(masm, FPU);
masm->MultiPopFPU(kCallerSavedFPU);
}
masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
@@ -683,27 +681,6 @@
FPURegister double_scratch1,
Label* not_int32);
- // Generate non FPU code to check if a double can be exactly represented by a
- // 32-bit integer. This does not check for 0 or -0, which need
- // to be checked for separately.
- // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
- // through otherwise.
- // src1 and src2 will be cloberred.
- //
- // Expected input:
- // - src1: higher (exponent) part of the double value.
- // - src2: lower (mantissa) part of the double value.
- // Output status:
- // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
- // - src2: contains 1.
- // - other registers are clobbered.
- static void DoubleIs32BitInteger(MacroAssembler* masm,
- Register src1,
- Register src2,
- Register dst,
- Register scratch,
- Label* not_int32);
-
// Generates code to call a C function to do a double operation using core
// registers. (Used when FPU is not supported.)
// This code never falls through, but returns with a heap number containing
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index bd403ce..e874a08 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -62,7 +62,6 @@
UnaryMathFunction CreateExpFunction() {
- if (!CpuFeatures::IsSupported(FPU)) return &exp;
if (!FLAG_fast_math) return &exp;
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
@@ -72,7 +71,6 @@
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
{
- CpuFeatureScope use_fpu(&masm, FPU);
DoubleRegister input = f12;
DoubleRegister result = f0;
DoubleRegister double_scratch1 = f4;
@@ -94,7 +92,7 @@
if (!IsMipsSoftFloatABI) {
// Result is already in f0, nothing to do.
} else {
- __ Move(a0, a1, result);
+ __ Move(v0, v1, result);
}
__ Ret();
}
@@ -184,7 +182,6 @@
// -- t0 : scratch (elements)
// -----------------------------------
Label loop, entry, convert_hole, gc_required, only_change_map, done;
- bool fpu_supported = CpuFeatures::IsSupported(FPU);
Register scratch = t6;
@@ -249,8 +246,6 @@
// t2: end of destination FixedDoubleArray, not tagged
// t3: begin of FixedDoubleArray element fields, not tagged
- if (!fpu_supported) __ Push(a1, a0);
-
__ Branch(&entry);
__ bind(&only_change_map);
@@ -278,25 +273,11 @@
__ UntagAndJumpIfNotSmi(t5, t5, &convert_hole);
// Normal smi, convert to double and store.
- if (fpu_supported) {
- CpuFeatureScope scope(masm, FPU);
- __ mtc1(t5, f0);
- __ cvt_d_w(f0, f0);
- __ sdc1(f0, MemOperand(t3));
- __ Addu(t3, t3, kDoubleSize);
- } else {
- FloatingPointHelper::ConvertIntToDouble(masm,
- t5,
- FloatingPointHelper::kCoreRegisters,
- f0,
- a0,
- a1,
- t7,
- f0);
- __ sw(a0, MemOperand(t3)); // mantissa
- __ sw(a1, MemOperand(t3, kIntSize)); // exponent
- __ Addu(t3, t3, kDoubleSize);
- }
+ __ mtc1(t5, f0);
+ __ cvt_d_w(f0, f0);
+ __ sdc1(f0, MemOperand(t3));
+ __ Addu(t3, t3, kDoubleSize);
+
__ Branch(&entry);
// Hole found, store the-hole NaN.
@@ -315,7 +296,6 @@
__ bind(&entry);
__ Branch(&loop, lt, t3, Operand(t2));
- if (!fpu_supported) __ Pop(a1, a0);
__ pop(ra);
__ bind(&done);
}
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index 139e7db..5a0870f 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -61,8 +61,9 @@
// -mhard-float is passed to the compiler.
const bool IsMipsSoftFloatABI = false;
#elif(defined(__mips_soft_float) && __mips_soft_float != 0)
-// Not using floating-point coprocessor instructions. This flag is raised when
-// -msoft-float is passed to the compiler.
+// This flag is raised when -msoft-float is passed to the compiler.
+// Although FPU is a base requirement for v8, soft-float ABI is used
+// on soft-float systems with FPU kernel emulation.
const bool IsMipsSoftFloatABI = true;
#else
const bool IsMipsSoftFloatABI = true;
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index 7158e4f..7896f20 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -116,76 +116,93 @@
}
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
+// This structure comes from FullCodeGenerator::EmitBackEdgeBookkeeping.
+// The back edge bookkeeping code matches the pattern:
+//
+// sltu at, sp, t0 / slt at, a3, zero_reg (in case of count based interrupts)
+// beq at, zero_reg, ok
+// lui t9, <interrupt stub address> upper
+// ori t9, <interrupt stub address> lower
+// jalr t9
+// nop
+// ok-label ----- pc_after points here
+//
+// We patch the code to the following form:
+//
+// addiu at, zero_reg, 1
+// beq at, zero_reg, ok ;; Not changed
+// lui t9, <on-stack replacement address> upper
+// ori t9, <on-stack replacement address> lower
+// jalr t9 ;; Not changed
+// nop ;; Not changed
+// ok-label ----- pc_after points here
+
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
Address pc_after,
- Code* check_code,
+ Code* interrupt_code,
Code* replacement_code) {
- const int kInstrSize = Assembler::kInstrSize;
- // This structure comes from FullCodeGenerator::EmitBackEdgeBookkeeping.
- // The call of the stack guard check has the following form:
- // sltu at, sp, t0 / slt at, a3, zero_reg (in case of count based interrupts)
- // beq at, zero_reg, ok
- // lui t9, <stack guard address> upper
- // ori t9, <stack guard address> lower
- // jalr t9
- // nop
- // ----- pc_after points here
-
- ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
-
+ ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ static const int kInstrSize = Assembler::kInstrSize;
// Replace the sltu instruction with load-imm 1 to at, so beq is not taken.
CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
patcher.masm()->addiu(at, zero_reg, 1);
-
// Replace the stack check address in the load-immediate (lui/ori pair)
// with the entry address of the replacement code.
- ASSERT(reinterpret_cast<uint32_t>(
- Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
- reinterpret_cast<uint32_t>(check_code->entry()));
Assembler::set_target_address_at(pc_after - 4 * kInstrSize,
replacement_code->entry());
- // We patched the code to the following form:
- // addiu at, zero_reg, 1
- // beq at, zero_reg, ok ;; Not changed
- // lui t9, <on-stack replacement address> upper
- // ori t9, <on-stack replacement address> lower
- // jalr t9 ;; Not changed
- // nop ;; Not changed
- // ----- pc_after points here
-
unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
unoptimized_code, pc_after - 4 * kInstrSize, replacement_code);
}
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
- // Exact opposite of the function above.
- const int kInstrSize = Assembler::kInstrSize;
- ASSERT(Assembler::IsAddImmediate(
- Assembler::instr_at(pc_after - 6 * kInstrSize)));
- ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
-
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ static const int kInstrSize = Assembler::kInstrSize;
// Restore the sltu instruction so beq can be taken again.
CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
patcher.masm()->slt(at, a3, zero_reg);
-
- // Replace the on-stack replacement address in the load-immediate (lui/ori
- // pair) with the entry address of the normal stack-check code.
- ASSERT(reinterpret_cast<uint32_t>(
- Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
- reinterpret_cast<uint32_t>(replacement_code->entry()));
+ // Restore the original call address.
Assembler::set_target_address_at(pc_after - 4 * kInstrSize,
- check_code->entry());
+ interrupt_code->entry());
- check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
- unoptimized_code, pc_after - 4 * kInstrSize, check_code);
+ interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+ unoptimized_code, pc_after - 4 * kInstrSize, interrupt_code);
}
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ static const int kInstrSize = Assembler::kInstrSize;
+ ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
+ if (Assembler::IsAddImmediate(
+ Assembler::instr_at(pc_after - 6 * kInstrSize))) {
+ ASSERT(reinterpret_cast<uint32_t>(
+ Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
+ reinterpret_cast<uint32_t>(replacement_code->entry()));
+ return true;
+ } else {
+ ASSERT(reinterpret_cast<uint32_t>(
+ Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
+ reinterpret_cast<uint32_t>(interrupt_code->entry()));
+ return false;
+ }
+}
+#endif // DEBUG
+
+
static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
ByteArray* translations = data->TranslationByteArray();
int length = data->DeoptCount();
@@ -586,17 +603,12 @@
const int kDoubleRegsSize =
kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- // Save all FPU registers before messing with them.
- __ Subu(sp, sp, Operand(kDoubleRegsSize));
- for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
- FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
- int offset = i * kDoubleSize;
- __ sdc1(fpu_reg, MemOperand(sp, offset));
- }
- } else {
- __ Subu(sp, sp, Operand(kDoubleRegsSize));
+ // Save all FPU registers before messing with them.
+ __ Subu(sp, sp, Operand(kDoubleRegsSize));
+ for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
+ FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
+ int offset = i * kDoubleSize;
+ __ sdc1(fpu_reg, MemOperand(sp, offset));
}
// Push saved_regs (needed to populate FrameDescription::registers_).
@@ -669,16 +681,13 @@
}
int double_regs_offset = FrameDescription::double_registers_offset();
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- // Copy FPU registers to
- // double_registers_[DoubleRegister::kNumAllocatableRegisters]
- for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
- int dst_offset = i * kDoubleSize + double_regs_offset;
- int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
- __ ldc1(f0, MemOperand(sp, src_offset));
- __ sdc1(f0, MemOperand(a1, dst_offset));
- }
+ // Copy FPU registers to
+ // double_registers_[DoubleRegister::kNumAllocatableRegisters]
+ for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
+ int dst_offset = i * kDoubleSize + double_regs_offset;
+ int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
+ __ ldc1(f0, MemOperand(sp, src_offset));
+ __ sdc1(f0, MemOperand(a1, dst_offset));
}
// Remove the bailout id, eventually return address, and the saved registers
@@ -747,15 +756,11 @@
__ bind(&outer_loop_header);
__ Branch(&outer_push_loop, lt, t0, Operand(a1));
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
-
- __ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
- for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
- const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
- int src_offset = i * kDoubleSize + double_regs_offset;
- __ ldc1(fpu_reg, MemOperand(a1, src_offset));
- }
+ __ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
+ for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
+ const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
+ int src_offset = i * kDoubleSize + double_regs_offset;
+ __ ldc1(fpu_reg, MemOperand(a1, src_offset));
}
// Push state, pc, and continuation from the last output frame.
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 0eca71f..b787f13 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -1051,8 +1051,8 @@
buffer[0] = '\0';
byte* prev_pc = pc;
pc += d.InstructionDecode(buffer, pc);
- fprintf(f, "%p %08x %s\n",
- prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
+ v8::internal::PrintF(f, "%p %08x %s\n",
+ prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
}
}
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 1568ce6..f6f20cd 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -152,18 +152,6 @@
// ----------------------------------------------------
-class StackHandlerConstants : public AllStatic {
- public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kCodeOffset = 1 * kPointerSize;
- static const int kStateOffset = 2 * kPointerSize;
- static const int kContextOffset = 3 * kPointerSize;
- static const int kFPOffset = 4 * kPointerSize;
-
- static const int kSize = kFPOffset + kPointerSize;
-};
-
-
class EntryFrameConstants : public AllStatic {
public:
static const int kCallerFPOffset = -3 * kPointerSize;
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 3e7c8da..8e2d5ab 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -170,8 +170,6 @@
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
- int locals_count = info->scope()->num_stack_slots();
-
info->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
@@ -183,6 +181,9 @@
__ Addu(fp, sp, Operand(2 * kPointerSize));
{ Comment cmnt(masm_, "[ Allocate locals");
+ int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
for (int i = 0; i < locals_count; i++) {
__ push(at);
}
@@ -673,17 +674,9 @@
Label* if_true,
Label* if_false,
Label* fall_through) {
- if (CpuFeatures::IsSupported(FPU)) {
- ToBooleanStub stub(result_register());
- __ CallStub(&stub, condition->test_id());
- __ mov(at, zero_reg);
- } else {
- // Call the runtime to find the boolean value of the source and then
- // translate it into control flow to the pair of labels.
- __ push(result_register());
- __ CallRuntime(Runtime::kToBool, 1);
- __ LoadRoot(at, Heap::kFalseValueRootIndex);
- }
+ ToBooleanStub stub(result_register());
+ __ CallStub(&stub, condition->test_id());
+ __ mov(at, zero_reg);
Split(ne, v0, Operand(at), if_true, if_false, fall_through);
}
@@ -1276,7 +1269,7 @@
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->language_mode());
+ FastNewClosureStub stub(info->language_mode(), info->is_generator());
__ li(a0, Operand(info));
__ push(a0);
__ CallStub(&stub);
@@ -1737,7 +1730,6 @@
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
__ li(a2, Operand(Smi::FromInt(expr->literal_index())));
__ li(a1, Operand(constant_elements));
- __ Push(a3, a2, a1);
if (has_fast_elements && constant_elements_values->map() ==
isolate()->heap()->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
@@ -1748,8 +1740,11 @@
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(),
1, a1, a2);
} else if (expr->depth() > 1) {
+ __ Push(a3, a2, a1);
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
- } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ } else if (Serializer::enabled() ||
+ length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ Push(a3, a2, a1);
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -3042,31 +3037,21 @@
// Convert 32 random bits in v0 to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
- if (CpuFeatures::IsSupported(FPU)) {
- __ PrepareCallCFunction(1, a0);
- __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
- __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+ __ PrepareCallCFunction(1, a0);
+ __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+ __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
- CpuFeatureScope scope(masm(), FPU);
- // 0x41300000 is the top half of 1.0 x 2^20 as a double.
- __ li(a1, Operand(0x41300000));
- // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
- __ Move(f12, v0, a1);
- // Move 0x4130000000000000 to FPU.
- __ Move(f14, zero_reg, a1);
- // Subtract and store the result in the heap number.
- __ sub_d(f0, f12, f14);
- __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
- __ mov(v0, s0);
- } else {
- __ PrepareCallCFunction(2, a0);
- __ mov(a0, s0);
- __ lw(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
- __ lw(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
- __ CallCFunction(
- ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
- }
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ __ li(a1, Operand(0x41300000));
+ // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
+ __ Move(f12, v0, a1);
+ // Move 0x4130000000000000 to FPU.
+ __ Move(f14, zero_reg, a1);
+ // Subtract and store the result in the heap number.
+ __ sub_d(f0, f12, f14);
+ __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
+ __ mov(v0, s0);
context()->Plug(v0);
}
@@ -3204,12 +3189,8 @@
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- if (CpuFeatures::IsSupported(FPU)) {
- MathPowStub stub(MathPowStub::ON_STACK);
- __ CallStub(&stub);
- } else {
- __ CallRuntime(Runtime::kMath_pow, 2);
- }
+ MathPowStub stub(MathPowStub::ON_STACK);
+ __ CallStub(&stub);
context()->Plug(v0);
}
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index b5d6c45..59cfcd9 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -65,7 +65,6 @@
HPhase phase("Z_Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
- CpuFeatureScope scope(masm(), FPU);
// Open a frame scope to indicate that there is a frame on the stack. The
// NONE indicates that the scope shouldn't actually generate code to set up
@@ -114,7 +113,7 @@
// issues when the stack allocated buffer goes out of scope.
size_t length = builder.position();
Vector<char> copy = Vector<char>::New(length + 1);
- memcpy(copy.start(), builder.Finalize(), copy.length());
+ OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
masm()->RecordComment(copy.start());
}
@@ -193,8 +192,7 @@
}
}
- if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
+ if (info()->saves_caller_doubles()) {
Comment(";;; Save clobbered callee double registers");
int count = 0;
BitVector* doubles = chunk()->allocated_double_registers();
@@ -829,7 +827,9 @@
}
ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS.
- if (FLAG_deopt_every_n_times == 1 && info_->opt_count() == id) {
+ if (FLAG_deopt_every_n_times == 1 &&
+ !info()->IsStub() &&
+ info()->opt_count() == id) {
__ Jump(entry, RelocInfo::RUNTIME_ENTRY);
return;
}
@@ -1475,7 +1475,6 @@
void LCodeGen::DoConstantD(LConstantD* instr) {
ASSERT(instr->result()->IsDoubleRegister());
DoubleRegister result = ToDoubleRegister(instr->result());
- CpuFeatureScope scope(masm(), FPU);
double v = instr->value();
__ Move(result, v);
}
@@ -1666,7 +1665,6 @@
__ bind(&done);
} else {
ASSERT(instr->hydrogen()->representation().IsDouble());
- CpuFeatureScope scope(masm(), FPU);
FPURegister left_reg = ToDoubleRegister(left);
FPURegister right_reg = ToDoubleRegister(right);
FPURegister result_reg = ToDoubleRegister(instr->result());
@@ -1707,7 +1705,6 @@
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
- CpuFeatureScope scope(masm(), FPU);
DoubleRegister left = ToDoubleRegister(instr->left());
DoubleRegister right = ToDoubleRegister(instr->right());
DoubleRegister result = ToDoubleRegister(instr->result());
@@ -1817,7 +1814,6 @@
Register reg = ToRegister(instr->value());
EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
} else if (r.IsDouble()) {
- CpuFeatureScope scope(masm(), FPU);
DoubleRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
EmitBranchF(true_block, false_block, nue, reg, kDoubleRegZero);
@@ -1902,7 +1898,6 @@
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
- CpuFeatureScope scope(masm(), FPU);
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
Label not_heap_number;
@@ -1982,7 +1977,6 @@
EmitGoto(next_block);
} else {
if (instr->is_double()) {
- CpuFeatureScope scope(masm(), FPU);
// Compare left and right as doubles and load the
// resulting flags into the normal status register.
FPURegister left_reg = ToDoubleRegister(left);
@@ -2545,8 +2539,7 @@
__ push(v0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
- if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
+ if (info()->saves_caller_doubles()) {
ASSERT(NeedsEagerFrame());
BitVector* doubles = chunk()->allocated_double_registers();
BitVector::Iterator save_iterator(doubles);
@@ -2933,61 +2926,11 @@
__ sll(scratch0(), key, shift_size);
__ Addu(scratch0(), scratch0(), external_pointer);
}
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- __ lwc1(result, MemOperand(scratch0(), additional_offset));
- __ cvt_d_s(result, result);
- } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
- __ ldc1(result, MemOperand(scratch0(), additional_offset));
- }
- } else {
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- Register value = external_pointer;
- __ lw(value, MemOperand(scratch0(), additional_offset));
- __ And(sfpd_lo, value, Operand(kBinary32MantissaMask));
-
- __ srl(scratch0(), value, kBinary32MantissaBits);
- __ And(scratch0(), scratch0(),
- Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
-
- Label exponent_rebiased;
- __ Xor(at, scratch0(), Operand(0x00));
- __ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
-
- __ Xor(at, scratch0(), Operand(0xff));
- Label skip;
- __ Branch(&skip, ne, at, Operand(zero_reg));
- __ li(scratch0(), Operand(0x7ff));
- __ bind(&skip);
- __ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
-
- // Rebias exponent.
- __ Addu(scratch0(),
- scratch0(),
- Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
-
- __ bind(&exponent_rebiased);
- __ And(sfpd_hi, value, Operand(kBinary32SignMask));
- __ sll(at, scratch0(), HeapNumber::kMantissaBitsInTopWord);
- __ Or(sfpd_hi, sfpd_hi, at);
-
- // Shift mantissa.
- static const int kMantissaShiftForHiWord =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaShiftForLoWord =
- kBitsPerInt - kMantissaShiftForHiWord;
-
- __ srl(at, sfpd_lo, kMantissaShiftForHiWord);
- __ Or(sfpd_hi, sfpd_hi, at);
- __ sll(sfpd_lo, sfpd_lo, kMantissaShiftForLoWord);
-
- } else {
- __ lw(sfpd_lo, MemOperand(scratch0(), additional_offset));
- __ lw(sfpd_hi, MemOperand(scratch0(),
- additional_offset + kPointerSize));
- }
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ __ lwc1(result, MemOperand(scratch0(), additional_offset));
+ __ cvt_d_s(result, result);
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
+ __ ldc1(result, MemOperand(scratch0(), additional_offset));
}
} else {
Register result = ToRegister(instr->result());
@@ -3062,21 +3005,11 @@
__ sll(scratch, key, shift_size);
__ Addu(elements, elements, scratch);
}
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- __ Addu(elements, elements, Operand(base_offset));
- __ ldc1(result, MemOperand(elements));
- if (instr->hydrogen()->RequiresHoleCheck()) {
- __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
- DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
- }
- } else {
- __ lw(sfpd_hi, MemOperand(elements, base_offset + kPointerSize));
- __ lw(sfpd_lo, MemOperand(elements, base_offset));
- if (instr->hydrogen()->RequiresHoleCheck()) {
- ASSERT(kPointerSize == sizeof(kHoleNanLower32));
- DeoptimizeIf(eq, instr->environment(), sfpd_hi, Operand(kHoleNanUpper32));
- }
+ __ Addu(elements, elements, Operand(base_offset));
+ __ ldc1(result, MemOperand(elements));
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+ DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
}
}
@@ -3445,7 +3378,7 @@
}
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
@@ -3510,7 +3443,7 @@
}
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
@@ -3523,20 +3456,18 @@
}
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
// Class for deferred case.
class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
public:
- DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
- LUnaryMathOperation* instr)
+ DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
}
virtual LInstruction* instr() { return instr_; }
private:
- LUnaryMathOperation* instr_;
+ LMathAbs* instr_;
};
Representation r = instr->hydrogen()->value()->representation();
@@ -3560,8 +3491,7 @@
}
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch1 = scratch0();
@@ -3589,8 +3519,7 @@
}
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathRound(LMathRound* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
@@ -3666,16 +3595,14 @@
}
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
__ sqrt_d(result, input);
}
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
- CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister temp = ToDoubleRegister(instr->temp());
@@ -3700,7 +3627,6 @@
void LCodeGen::DoPower(LPower* instr) {
- CpuFeatureScope scope(masm(), FPU);
Representation exponent_type = instr->hydrogen()->right()->representation();
// Having marked this as a call, we can use any registers.
// Just make sure that the input/output registers are the expected ones.
@@ -3731,7 +3657,6 @@
void LCodeGen::DoRandom(LRandom* instr) {
- CpuFeatureScope scope(masm(), FPU);
class DeferredDoRandom: public LDeferredCode {
public:
DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
@@ -3808,7 +3733,6 @@
void LCodeGen::DoMathExp(LMathExp* instr) {
- CpuFeatureScope scope(masm(), FPU);
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
@@ -3822,7 +3746,7 @@
}
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(f4));
TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::UNTAGGED);
@@ -3830,7 +3754,7 @@
}
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(f4));
TranscendentalCacheStub stub(TranscendentalCache::TAN,
TranscendentalCacheStub::UNTAGGED);
@@ -3838,7 +3762,7 @@
}
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(f4));
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
@@ -3846,7 +3770,7 @@
}
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(f4));
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
@@ -3854,42 +3778,6 @@
}
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
- switch (instr->op()) {
- case kMathAbs:
- DoMathAbs(instr);
- break;
- case kMathFloor:
- DoMathFloor(instr);
- break;
- case kMathRound:
- DoMathRound(instr);
- break;
- case kMathSqrt:
- DoMathSqrt(instr);
- break;
- case kMathPowHalf:
- DoMathPowHalf(instr);
- break;
- case kMathCos:
- DoMathCos(instr);
- break;
- case kMathSin:
- DoMathSin(instr);
- break;
- case kMathTan:
- DoMathTan(instr);
- break;
- case kMathLog:
- DoMathLog(instr);
- break;
- default:
- Abort("Unimplemented type of LUnaryMathOperation.");
- UNREACHABLE();
- }
-}
-
-
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(a1));
ASSERT(instr->HasPointerMap());
@@ -4111,7 +3999,6 @@
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
- CpuFeatureScope scope(masm(), FPU);
Register external_pointer = ToRegister(instr->elements());
Register key = no_reg;
ElementsKind elements_kind = instr->elements_kind();
@@ -4185,7 +4072,6 @@
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
- CpuFeatureScope scope(masm(), FPU);
DoubleRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Register key = no_reg;
@@ -4489,7 +4375,6 @@
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
- CpuFeatureScope scope(masm(), FPU);
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
LOperand* output = instr->result();
@@ -4507,7 +4392,6 @@
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
- CpuFeatureScope scope(masm(), FPU);
LOperand* input = instr->value();
LOperand* output = instr->result();
@@ -4569,45 +4453,6 @@
}
-// Convert unsigned integer with specified number of leading zeroes in binary
-// representation to IEEE 754 double.
-// Integer to convert is passed in register src.
-// Resulting double is returned in registers hiword:loword.
-// This functions does not work correctly for 0.
-static void GenerateUInt2Double(MacroAssembler* masm,
- Register src,
- Register hiword,
- Register loword,
- Register scratch,
- int leading_zeroes) {
- const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
- const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
-
- const int mantissa_shift_for_hi_word =
- meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
- const int mantissa_shift_for_lo_word =
- kBitsPerInt - mantissa_shift_for_hi_word;
- masm->li(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
- if (mantissa_shift_for_hi_word > 0) {
- masm->sll(loword, src, mantissa_shift_for_lo_word);
- masm->srl(hiword, src, mantissa_shift_for_hi_word);
- masm->Or(hiword, scratch, hiword);
- } else {
- masm->mov(loword, zero_reg);
- masm->sll(hiword, src, mantissa_shift_for_hi_word);
- masm->Or(hiword, scratch, hiword);
- }
-
- // If least significant bit of biased exponent was not 1 it was corrupted
- // by most significant bit of mantissa so we should fix that.
- if (!(biased_exponent & 1)) {
- masm->li(scratch, 1 << HeapNumber::kExponentShift);
- masm->nor(scratch, scratch, scratch);
- masm->and_(hiword, hiword, scratch);
- }
-}
-
-
void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
LOperand* value,
IntegerSignedness signedness) {
@@ -4628,35 +4473,11 @@
__ SmiUntag(src, dst);
__ Xor(src, src, Operand(0x80000000));
}
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- __ mtc1(src, dbl_scratch);
- __ cvt_d_w(dbl_scratch, dbl_scratch);
- } else {
- FloatingPointHelper::Destination dest =
- FloatingPointHelper::kCoreRegisters;
- FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, f0,
- sfpd_lo, sfpd_hi,
- scratch0(), f2);
- }
+ __ mtc1(src, dbl_scratch);
+ __ cvt_d_w(dbl_scratch, dbl_scratch);
} else {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- __ mtc1(src, dbl_scratch);
- __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
- } else {
- Label no_leading_zero, convert_done;
- __ And(at, src, Operand(0x80000000));
- __ Branch(&no_leading_zero, ne, at, Operand(zero_reg));
-
- // Integer has one leading zeros.
- GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 1);
- __ Branch(&convert_done);
-
- __ bind(&no_leading_zero);
- GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 0);
- __ bind(&convert_done);
- }
+ __ mtc1(src, dbl_scratch);
+ __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
}
if (FLAG_inline_new) {
@@ -4680,13 +4501,7 @@
// Done. Put the value in dbl_scratch into the value of the allocated heap
// number.
__ bind(&done);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
- } else {
- __ sw(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset));
- __ sw(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset));
- }
+ __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
__ Addu(dst, dst, kHeapObjectTag);
__ StoreToSafepointRegisterSlot(dst, dst);
}
@@ -4719,39 +4534,16 @@
Label no_special_nan_handling;
Label done;
if (convert_hole) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- DoubleRegister input_reg = ToDoubleRegister(instr->value());
- __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
- __ Move(reg, scratch0(), input_reg);
- Label canonicalize;
- __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
- __ li(reg, factory()->the_hole_value());
- __ Branch(&done);
- __ bind(&canonicalize);
- __ Move(input_reg,
- FixedDoubleArray::canonical_not_the_hole_nan_as_double());
- } else {
- Label not_hole;
- __ Branch(¬_hole, ne, sfpd_hi, Operand(kHoleNanUpper32));
- __ li(reg, factory()->the_hole_value());
- __ Branch(&done);
- __ bind(¬_hole);
- __ And(scratch, sfpd_hi, Operand(0x7ff00000));
- __ Branch(&no_special_nan_handling, ne, scratch, Operand(0x7ff00000));
- Label special_nan_handling;
- __ And(at, sfpd_hi, Operand(0x000FFFFF));
- __ Branch(&special_nan_handling, ne, at, Operand(zero_reg));
- __ Branch(&no_special_nan_handling, eq, sfpd_lo, Operand(zero_reg));
- __ bind(&special_nan_handling);
- double canonical_nan =
- FixedDoubleArray::canonical_not_the_hole_nan_as_double();
- uint64_t casted_nan = BitCast<uint64_t>(canonical_nan);
- __ li(sfpd_lo,
- Operand(static_cast<uint32_t>(casted_nan & 0xFFFFFFFF)));
- __ li(sfpd_hi,
- Operand(static_cast<uint32_t>(casted_nan >> 32)));
- }
+ DoubleRegister input_reg = ToDoubleRegister(instr->value());
+ __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
+ __ Move(reg, scratch0(), input_reg);
+ Label canonicalize;
+ __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
+ __ li(reg, factory()->the_hole_value());
+ __ Branch(&done);
+ __ bind(&canonicalize);
+ __ Move(input_reg,
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double());
}
__ bind(&no_special_nan_handling);
@@ -4765,13 +4557,7 @@
__ Branch(deferred->entry());
}
__ bind(deferred->exit());
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm(), FPU);
- __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
- } else {
- __ sw(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset));
- __ sw(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize));
- }
+ __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
// Now that we have finished with the object's real address tag it
__ Addu(reg, reg, kHeapObjectTag);
__ bind(&done);
@@ -4821,7 +4607,6 @@
LEnvironment* env,
NumberUntagDMode mode) {
Register scratch = scratch0();
- CpuFeatureScope scope(masm(), FPU);
Label load_smi, heap_number, done;
@@ -4899,7 +4684,6 @@
// of the if.
if (instr->truncating()) {
- CpuFeatureScope scope(masm(), FPU);
Register scratch3 = ToRegister(instr->temp2());
FPURegister single_scratch = double_scratch.low();
ASSERT(!scratch3.is(input_reg) &&
@@ -5154,7 +4938,6 @@
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
- CpuFeatureScope vfp_scope(masm(), FPU);
DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
@@ -5163,7 +4946,6 @@
void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
- CpuFeatureScope vfp_scope(masm(), FPU);
Register unclamped_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
__ ClampUint8(result_reg, unclamped_reg);
@@ -5171,7 +4953,6 @@
void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
- CpuFeatureScope vfp_scope(masm(), FPU);
Register scratch = scratch0();
Register input_reg = ToRegister(instr->unclamped());
Register result_reg = ToRegister(instr->result());
@@ -5207,7 +4988,6 @@
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
- ASSERT(instr->temp()->Equals(instr->result()));
Register prototype_reg = ToRegister(instr->temp());
Register map_reg = ToRegister(instr->temp2());
@@ -5220,8 +5000,6 @@
for (int i = 0; i < maps->length(); i++) {
prototype_maps_.Add(maps->at(i), info()->zone());
}
- __ LoadHeapObject(prototype_reg,
- prototypes->at(prototypes->length() - 1));
} else {
for (int i = 0; i < prototypes->length(); i++) {
__ LoadHeapObject(prototype_reg, prototypes->at(i));
@@ -5337,11 +5115,11 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+ }
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- }
__ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
@@ -5369,7 +5147,13 @@
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ SmiTag(size, size);
__ push(size);
- CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInOldPointerSpace, 1, instr);
+ } else {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInNewSpace, 1, instr);
+ }
__ StoreToSafepointRegisterSlot(v0, result);
}
@@ -5405,7 +5189,6 @@
// Boilerplate already exists, constant elements are never accessed.
// Pass an empty fixed array.
__ li(a1, Operand(isolate()->factory()->empty_fixed_array()));
- __ Push(a3, a2, a1);
// Pick the right runtime function or stub to call.
int length = instr->hydrogen()->length();
@@ -5416,8 +5199,10 @@
FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else if (instr->hydrogen()->depth() > 1) {
+ __ Push(a3, a2, a1);
CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ Push(a3, a2, a1);
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
} else {
FastCloneShallowArrayStub::Mode mode =
@@ -5430,170 +5215,6 @@
}
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
- Register result,
- Register source,
- int* offset,
- AllocationSiteMode mode) {
- ASSERT(!source.is(a2));
- ASSERT(!result.is(a2));
-
- bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
- object->map()->CanTrackAllocationSite();
-
- // Only elements backing stores for non-COW arrays need to be copied.
- Handle<FixedArrayBase> elements(object->elements());
- bool has_elements = elements->length() > 0 &&
- elements->map() != isolate()->heap()->fixed_cow_array_map();
-
- // Increase the offset so that subsequent objects end up right after
- // this object and its backing store.
- int object_offset = *offset;
- int object_size = object->map()->instance_size();
- int elements_size = has_elements ? elements->Size() : 0;
- int elements_offset = *offset + object_size;
- if (create_allocation_site_info) {
- elements_offset += AllocationSiteInfo::kSize;
- *offset += AllocationSiteInfo::kSize;
- }
-
- *offset += object_size + elements_size;
-
- // Copy object header.
- ASSERT(object->properties()->length() == 0);
- int inobject_properties = object->map()->inobject_properties();
- int header_size = object_size - inobject_properties * kPointerSize;
- for (int i = 0; i < header_size; i += kPointerSize) {
- if (has_elements && i == JSObject::kElementsOffset) {
- __ Addu(a2, result, Operand(elements_offset));
- } else {
- __ lw(a2, FieldMemOperand(source, i));
- }
- __ sw(a2, FieldMemOperand(result, object_offset + i));
- }
-
- // Copy in-object properties.
- for (int i = 0; i < inobject_properties; i++) {
- int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
- Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
- isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ Addu(a2, result, Operand(*offset));
- __ sw(a2, FieldMemOperand(result, total_offset));
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(a2, Handle<HeapObject>::cast(value));
- __ sw(a2, FieldMemOperand(result, total_offset));
- } else {
- __ li(a2, Operand(value));
- __ sw(a2, FieldMemOperand(result, total_offset));
- }
- }
-
- // Build Allocation Site Info if desired
- if (create_allocation_site_info) {
- __ li(a2, Operand(Handle<Map>(isolate()->heap()->
- allocation_site_info_map())));
- __ sw(a2, FieldMemOperand(result, object_size));
- __ sw(source, FieldMemOperand(result, object_size + kPointerSize));
- }
-
- if (has_elements) {
- // Copy elements backing store header.
- __ LoadHeapObject(source, elements);
- for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
- __ lw(a2, FieldMemOperand(source, i));
- __ sw(a2, FieldMemOperand(result, elements_offset + i));
- }
-
- // Copy elements backing store content.
- int elements_length = has_elements ? elements->length() : 0;
- if (elements->IsFixedDoubleArray()) {
- Handle<FixedDoubleArray> double_array =
- Handle<FixedDoubleArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int64_t value = double_array->get_representation(i);
- // We only support little endian mode...
- int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
- int32_t value_high = static_cast<int32_t>(value >> 32);
- int total_offset =
- elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
- __ li(a2, Operand(value_low));
- __ sw(a2, FieldMemOperand(result, total_offset));
- __ li(a2, Operand(value_high));
- __ sw(a2, FieldMemOperand(result, total_offset + 4));
- }
- } else if (elements->IsFixedArray()) {
- Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value(fast_elements->get(i), isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ Addu(a2, result, Operand(*offset));
- __ sw(a2, FieldMemOperand(result, total_offset));
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(a2, Handle<HeapObject>::cast(value));
- __ sw(a2, FieldMemOperand(result, total_offset));
- } else {
- __ li(a2, Operand(value));
- __ sw(a2, FieldMemOperand(result, total_offset));
- }
- }
- } else {
- UNREACHABLE();
- }
- }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
- int size = instr->hydrogen()->total_size();
- ElementsKind boilerplate_elements_kind =
- instr->hydrogen()->boilerplate()->GetElementsKind();
-
- // Deopt if the array literal boilerplate ElementsKind is of a type different
- // than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
- if (CanTransitionToMoreGeneralFastElementsKind(
- boilerplate_elements_kind, true)) {
- __ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
- // Load map into a2.
- __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
- // Load the map's "bit field 2".
- __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
- // Retrieve elements_kind from bit field 2.
- __ Ext(a2, a2, Map::kElementsKindShift, Map::kElementsKindBitCount);
- DeoptimizeIf(ne, instr->environment(), a2,
- Operand(boilerplate_elements_kind));
- }
-
- // Allocate all objects that are part of the literal in one big
- // allocation. This avoids multiple limit checks.
- Label allocated, runtime_allocate;
- __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
- __ jmp(&allocated);
-
- __ bind(&runtime_allocate);
- __ li(a0, Operand(Smi::FromInt(size)));
- __ push(a0);
- CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
- __ bind(&allocated);
- int offset = 0;
- __ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
- EmitDeepCopy(instr->hydrogen()->boilerplate(), v0, a1, &offset,
- instr->hydrogen()->allocation_site_mode());
- ASSERT_EQ(size, offset);
-}
-
-
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
Handle<FixedArray> literals(instr->environment()->closure()->literals());
@@ -5691,7 +5312,8 @@
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode());
+ FastNewClosureStub stub(shared_info->language_mode(),
+ shared_info->is_generator());
__ li(a1, Operand(shared_info));
__ push(a1);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index bb2003f..a1bc4ba 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -132,7 +132,7 @@
IntegerSignedness signedness);
void DoDeferredTaggedToI(LTaggedToI* instr);
- void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+ void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -289,17 +289,7 @@
Register ToRegister(int index) const;
DoubleRegister ToDoubleRegister(int index) const;
- // Specific math operations - used from DoUnaryMathOperation.
- void EmitIntegerMathAbs(LUnaryMathOperation* instr);
- void DoMathAbs(LUnaryMathOperation* instr);
- void DoMathFloor(LUnaryMathOperation* instr);
- void DoMathRound(LUnaryMathOperation* instr);
- void DoMathSqrt(LUnaryMathOperation* instr);
- void DoMathPowHalf(LUnaryMathOperation* instr);
- void DoMathLog(LUnaryMathOperation* instr);
- void DoMathTan(LUnaryMathOperation* instr);
- void DoMathCos(LUnaryMathOperation* instr);
- void DoMathSin(LUnaryMathOperation* instr);
+ void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers,
diff --git a/src/mips/lithium-gap-resolver-mips.cc b/src/mips/lithium-gap-resolver-mips.cc
index b415156..87efae5 100644
--- a/src/mips/lithium-gap-resolver-mips.cc
+++ b/src/mips/lithium-gap-resolver-mips.cc
@@ -172,10 +172,8 @@
} else if (source->IsStackSlot()) {
__ lw(kLithiumScratchReg, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
__ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
__ ldc1(kLithiumScratchDouble, cgen_->ToMemOperand(source));
} else {
UNREACHABLE();
@@ -195,11 +193,9 @@
} else if (saved_destination_->IsStackSlot()) {
__ sw(kLithiumScratchReg, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
__ mov_d(cgen_->ToDoubleRegister(saved_destination_),
kLithiumScratchDouble);
} else if (saved_destination_->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
__ sdc1(kLithiumScratchDouble,
cgen_->ToMemOperand(saved_destination_));
} else {
@@ -236,7 +232,6 @@
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
if (!destination_operand.OffsetIsInt16Encodable()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
// 'at' is overwritten while saving the value to the destination.
// Therefore we can't use 'at'. It is OK if the read from the source
// destroys 'at', since that happens before the value is read.
@@ -276,7 +271,6 @@
}
} else if (source->IsDoubleRegister()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
DoubleRegister source_register = cgen_->ToDoubleRegister(source);
if (destination->IsDoubleRegister()) {
__ mov_d(cgen_->ToDoubleRegister(destination), source_register);
@@ -287,7 +281,6 @@
}
} else if (source->IsDoubleStackSlot()) {
- CpuFeatureScope scope(cgen_->masm(), FPU);
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsDoubleRegister()) {
__ ldc1(cgen_->ToDoubleRegister(destination), source_operand);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 652c7ca..afa806c 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -302,17 +302,6 @@
}
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
- stream->Add("/%s ", hydrogen()->OpName());
- value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
- value()->PrintTo(stream);
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -1123,50 +1112,103 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
- BuiltinFunctionId op = instr->op();
- if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
- LOperand* input = UseFixedDouble(instr->value(), f4);
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
- return MarkAsCall(DefineFixedDouble(result, f4), instr);
- } else if (op == kMathExp) {
- ASSERT(instr->representation().IsDouble());
- ASSERT(instr->value()->representation().IsDouble());
- LOperand* input = UseTempRegister(instr->value());
- LOperand* temp1 = TempRegister();
- LOperand* temp2 = TempRegister();
- LOperand* double_temp = FixedTemp(f6); // Chosen by fair dice roll.
- LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
- return DefineAsRegister(result);
- } else if (op == kMathPowHalf) {
- // Input cannot be the same as the result.
- // See lithium-codegen-mips.cc::DoMathPowHalf.
- LOperand* input = UseFixedDouble(instr->value(), f8);
- LOperand* temp = FixedTemp(f6);
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
- return DefineFixedDouble(result, f4);
- } else {
- LOperand* input = UseRegister(instr->value());
-
- LOperand* temp = (op == kMathRound) ? FixedTemp(f6) :
- (op == kMathFloor) ? TempRegister() : NULL;
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
- switch (op) {
- case kMathAbs:
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
- case kMathFloor:
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
- case kMathSqrt:
- return DefineAsRegister(result);
- case kMathRound:
- return AssignEnvironment(DefineAsRegister(result));
- default:
- UNREACHABLE();
- return NULL;
- }
+ switch (instr->op()) {
+ case kMathFloor: return DoMathFloor(instr);
+ case kMathRound: return DoMathRound(instr);
+ case kMathAbs: return DoMathAbs(instr);
+ case kMathLog: return DoMathLog(instr);
+ case kMathSin: return DoMathSin(instr);
+ case kMathCos: return DoMathCos(instr);
+ case kMathTan: return DoMathTan(instr);
+ case kMathExp: return DoMathExp(instr);
+ case kMathSqrt: return DoMathSqrt(instr);
+ case kMathPowHalf: return DoMathPowHalf(instr);
+ default:
+ UNREACHABLE();
+ return NULL;
}
}
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), f4);
+ LMathLog* result = new(zone()) LMathLog(input);
+ return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), f4);
+ LMathSin* result = new(zone()) LMathSin(input);
+ return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), f4);
+ LMathCos* result = new(zone()) LMathCos(input);
+ return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), f4);
+ LMathTan* result = new(zone()) LMathTan(input);
+ return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* input = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LOperand* double_temp = FixedTemp(f6); // Chosen by fair dice roll.
+ LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
+ return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+ // Input cannot be the same as the result, see LCodeGen::DoMathPowHalf.
+ LOperand* input = UseFixedDouble(instr->value(), f8);
+ LOperand* temp = FixedTemp(f6);
+ LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
+ return DefineFixedDouble(result, f4);
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LMathAbs* result = new(zone()) LMathAbs(input);
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LOperand* temp = TempRegister();
+ LMathFloor* result = new(zone()) LMathFloor(input, temp);
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LMathSqrt* result = new(zone()) LMathSqrt(input);
+ return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegister(instr->value());
+ LOperand* temp = FixedTemp(f6);
+ LMathRound* result = new(zone()) LMathRound(input, temp);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
argument_count_ -= instr->argument_count();
@@ -1807,7 +1849,7 @@
LUnallocated* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2);
- return AssignEnvironment(Define(result, temp1));
+ return AssignEnvironment(result);
}
@@ -2008,16 +2050,7 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
- // float->double conversion on non-VFP2 requires an extra scratch
- // register. For convenience, just mark the elements register as "UseTemp"
- // so that it can be used as a temp during the float->double conversion
- // after it's no longer needed after the float load.
- bool needs_temp =
- !CpuFeatures::IsSupported(FPU) &&
- (elements_kind == EXTERNAL_FLOAT_ELEMENTS);
- LOperand* external_pointer = needs_temp
- ? UseTempRegister(instr->elements())
- : UseRegister(instr->elements());
+ LOperand* external_pointer = UseRegister(instr->elements());
result = new(zone()) LLoadKeyed(external_pointer, key);
}
@@ -2217,11 +2250,6 @@
}
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
- return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, v0), instr);
-}
-
-
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, v0), instr);
}
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index e995905..b0fc59a 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -97,7 +97,6 @@
V(DoubleToI) \
V(DummyUse) \
V(ElementsKind) \
- V(FastLiteral) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
@@ -134,8 +133,17 @@
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
+ V(MathAbs) \
+ V(MathCos) \
V(MathExp) \
+ V(MathFloor) \
+ V(MathLog) \
V(MathMinMax) \
+ V(MathPowHalf) \
+ V(MathRound) \
+ V(MathSin) \
+ V(MathSqrt) \
+ V(MathTan) \
V(ModI) \
V(MulI) \
V(MultiplyAddD) \
@@ -178,7 +186,6 @@
V(TrapAllocationMemento) \
V(Typeof) \
V(TypeofIsAndBranch) \
- V(UnaryMathOperation) \
V(UnknownOSRValue) \
V(ValueOf) \
V(ForInPrepareMap) \
@@ -663,9 +670,9 @@
};
-class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
+class LMathFloor: public LTemplateInstruction<1, 1, 1> {
public:
- LUnaryMathOperation(LOperand* value, LOperand* temp) {
+ LMathFloor(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
@@ -673,11 +680,84 @@
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
- DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+ DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
- virtual void PrintDataTo(StringStream* stream);
- BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathRound: public LTemplateInstruction<1, 1, 1> {
+ public:
+ LMathRound(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathAbs(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathLog(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSin(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathCos(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathTan(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
};
@@ -700,8 +780,32 @@
LOperand* double_temp() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
- virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSqrt(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf: public LTemplateInstruction<1, 1, 1> {
+ public:
+ LMathPowHalf(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
};
@@ -1255,7 +1359,7 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+ DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
};
@@ -2184,7 +2288,7 @@
};
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
public:
LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) {
temps_[0] = temp;
@@ -2300,13 +2404,6 @@
};
-class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
- public:
- DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
- DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
@@ -2550,6 +2647,17 @@
LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
+ LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+ LInstruction* DoMathRound(HUnaryMathOperation* instr);
+ LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+ LInstruction* DoMathLog(HUnaryMathOperation* instr);
+ LInstruction* DoMathSin(HUnaryMathOperation* instr);
+ LInstruction* DoMathCos(HUnaryMathOperation* instr);
+ LInstruction* DoMathTan(HUnaryMathOperation* instr);
+ LInstruction* DoMathExp(HUnaryMathOperation* instr);
+ LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+ LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
private:
enum Status {
UNUSED,
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 12e1025..6f98914 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -369,7 +369,6 @@
// Check the context is a native context.
if (emit_debug_code()) {
- // TODO(119): Avoid push(holder_reg)/pop(holder_reg).
push(holder_reg); // Temporarily save holder on the stack.
// Read the first word and compare to the native_context_map.
lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
@@ -385,7 +384,6 @@
// Check the context is a native context.
if (emit_debug_code()) {
- // TODO(119): Avoid push(holder_reg)/pop(holder_reg).
push(holder_reg); // Temporarily save holder on the stack.
mov(holder_reg, at); // Move at to its holding place.
LoadRoot(at, Heap::kNullValueRootIndex);
@@ -853,7 +851,6 @@
void MacroAssembler::MultiPushFPU(RegList regs) {
- CpuFeatureScope scope(this, FPU);
int16_t num_to_push = NumberOfBitsSet(regs);
int16_t stack_offset = num_to_push * kDoubleSize;
@@ -868,7 +865,6 @@
void MacroAssembler::MultiPushReversedFPU(RegList regs) {
- CpuFeatureScope scope(this, FPU);
int16_t num_to_push = NumberOfBitsSet(regs);
int16_t stack_offset = num_to_push * kDoubleSize;
@@ -883,7 +879,6 @@
void MacroAssembler::MultiPopFPU(RegList regs) {
- CpuFeatureScope scope(this, FPU);
int16_t stack_offset = 0;
for (int16_t i = 0; i < kNumRegisters; i++) {
@@ -897,7 +892,6 @@
void MacroAssembler::MultiPopReversedFPU(RegList regs) {
- CpuFeatureScope scope(this, FPU);
int16_t stack_offset = 0;
for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
@@ -1170,7 +1164,6 @@
void MacroAssembler::Move(FPURegister dst, double imm) {
- ASSERT(IsEnabled(FPU));
static const DoubleRepresentation minus_zero(-0.0);
static const DoubleRepresentation zero(0.0);
DoubleRepresentation value(imm);
@@ -1340,61 +1333,17 @@
Subu(scratch2, scratch2, Operand(zero_exponent));
// Dest already has a Smi zero.
Branch(&done, lt, scratch2, Operand(zero_reg));
- if (!CpuFeatures::IsSupported(FPU)) {
- // We have a shifted exponent between 0 and 30 in scratch2.
- srl(dest, scratch2, HeapNumber::kExponentShift);
- // We now have the exponent in dest. Subtract from 30 to get
- // how much to shift down.
- li(at, Operand(30));
- subu(dest, at, dest);
- }
bind(&right_exponent);
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(this, FPU);
- // MIPS FPU instructions implementing double precision to integer
- // conversion using round to zero. Since the FP value was qualified
- // above, the resulting integer should be a legal int32.
- // The original 'Exponent' word is still in scratch.
- lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
- mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
- trunc_w_d(double_scratch, double_scratch);
- mfc1(dest, double_scratch);
- } else {
- // On entry, dest has final downshift, scratch has original sign/exp/mant.
- // Save sign bit in top bit of dest.
- And(scratch2, scratch, Operand(0x80000000));
- Or(dest, dest, Operand(scratch2));
- // Put back the implicit 1, just above mantissa field.
- Or(scratch, scratch, Operand(1 << HeapNumber::kExponentShift));
- // Shift up the mantissa bits to take up the space the exponent used to
- // take. We just orred in the implicit bit so that took care of one and
- // we want to leave the sign bit 0 so we subtract 2 bits from the shift
- // distance. But we want to clear the sign-bit so shift one more bit
- // left, then shift right one bit.
- const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
- sll(scratch, scratch, shift_distance + 1);
- srl(scratch, scratch, 1);
+ // MIPS FPU instructions implementing double precision to integer
+ // conversion using round to zero. Since the FP value was qualified
+ // above, the resulting integer should be a legal int32.
+ // The original 'Exponent' word is still in scratch.
+ lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
+ mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
+ trunc_w_d(double_scratch, double_scratch);
+ mfc1(dest, double_scratch);
- // Get the second half of the double. For some exponents we don't
- // actually need this because the bits get shifted out again, but
- // it's probably slower to test than just to do it.
- lw(scratch2, FieldMemOperand(source, HeapNumber::kMantissaOffset));
- // Extract the top 10 bits, and insert those bottom 10 bits of scratch.
- // The width of the field here is the same as the shift amount above.
- const int field_width = shift_distance;
- Ext(scratch2, scratch2, 32-shift_distance, field_width);
- Ins(scratch, scratch2, 0, field_width);
- // Move down according to the exponent.
- srlv(scratch, scratch, dest);
- // Prepare the negative version of our integer.
- subu(scratch2, zero_reg, scratch);
- // Trick to check sign bit (msb) held in dest, count leading zero.
- // 0 indicates negative, save negative version with conditional move.
- Clz(dest, dest);
- Movz(scratch, scratch2, dest);
- mov(dest, scratch);
- }
bind(&done);
}
@@ -1410,8 +1359,6 @@
ASSERT(!double_input.is(double_scratch));
ASSERT(!except_flag.is(scratch));
- ASSERT(CpuFeatures::IsSupported(FPU));
- CpuFeatureScope scope(this, FPU);
Label done;
// Clear the except flag (0 = no exception)
@@ -1553,7 +1500,6 @@
Register scratch,
Register scratch2,
Register scratch3) {
- CpuFeatureScope scope(this, FPU);
ASSERT(!scratch2.is(result));
ASSERT(!scratch3.is(result));
ASSERT(!scratch3.is(scratch2));
@@ -3461,11 +3407,7 @@
// scratch1 is now effective address of the double element
FloatingPointHelper::Destination destination;
- if (CpuFeatures::IsSupported(FPU)) {
- destination = FloatingPointHelper::kFPURegisters;
- } else {
- destination = FloatingPointHelper::kCoreRegisters;
- }
+ destination = FloatingPointHelper::kFPURegisters;
Register untagged_value = elements_reg;
SmiUntag(untagged_value, value_reg);
@@ -3478,7 +3420,6 @@
scratch4,
f2);
if (destination == FloatingPointHelper::kFPURegisters) {
- CpuFeatureScope scope(this, FPU);
sdc1(f0, MemOperand(scratch1, 0));
} else {
sw(mantissa_reg, MemOperand(scratch1, 0));
@@ -3571,7 +3512,6 @@
void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
- CpuFeatureScope scope(this, FPU);
if (IsMipsSoftFloatABI) {
Move(dst, v0, v1);
} else {
@@ -3581,7 +3521,6 @@
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
- CpuFeatureScope scope(this, FPU);
if (!IsMipsSoftFloatABI) {
Move(f12, dreg);
} else {
@@ -3592,7 +3531,6 @@
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
DoubleRegister dreg2) {
- CpuFeatureScope scope(this, FPU);
if (!IsMipsSoftFloatABI) {
if (dreg2.is(f12)) {
ASSERT(!dreg1.is(f14));
@@ -3611,7 +3549,6 @@
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg,
Register reg) {
- CpuFeatureScope scope(this, FPU);
if (!IsMipsSoftFloatABI) {
Move(f12, dreg);
Move(a2, reg);
@@ -4254,10 +4191,7 @@
const Runtime::Function* function = Runtime::FunctionForId(id);
PrepareCEntryArgs(function->nargs);
PrepareCEntryFunction(ExternalReference(function, isolate()));
- SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
- ? kSaveFPRegs
- : kDontSaveFPRegs;
- CEntryStub stub(1, mode);
+ CEntryStub stub(1, kSaveFPRegs);
CallStub(&stub);
}
@@ -4649,7 +4583,6 @@
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
if (save_doubles) {
- CpuFeatureScope scope(this, FPU);
// The stack must be allign to 0 modulo 8 for stores with sdc1.
ASSERT(kDoubleSize == frame_alignment);
if (frame_alignment > 0) {
@@ -4687,7 +4620,6 @@
bool do_return) {
// Optionally restore all double registers.
if (save_doubles) {
- CpuFeatureScope scope(this, FPU);
// Remember: we only need to restore every 2nd double FPU value.
lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset));
for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) {
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 5eb79eb..bc38435 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -867,7 +867,7 @@
Instruction::kInstrSize) == 0);
} else {
// Cache miss. Load memory into the cache.
- memcpy(cached_line, line, CachePage::kLineLength);
+ OS::MemCopy(cached_line, line, CachePage::kLineLength);
*cache_valid_byte = CachePage::LINE_VALID;
}
}
@@ -1059,8 +1059,8 @@
// Read the bits from the unsigned integer register_[] array
// into the double precision floating point value and return it.
char buffer[2 * sizeof(registers_[0])];
- memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
- memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+ OS::MemCopy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
+ OS::MemCopy(&dm_val, buffer, 2 * sizeof(registers_[0]));
return(dm_val);
}
@@ -1091,12 +1091,14 @@
}
-// For use in calls that take two double values, constructed either
+// Runtime FP routines take up to two double arguments and zero
+// or one integer arguments. All are constructed here,
// from a0-a3 or f12 and f14.
-void Simulator::GetFpArgs(double* x, double* y) {
+void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
if (!IsMipsSoftFloatABI) {
*x = get_fpu_register_double(12);
*y = get_fpu_register_double(14);
+ *z = get_register(a2);
} else {
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
@@ -1106,53 +1108,14 @@
// Registers a0 and a1 -> x.
reg_buffer[0] = get_register(a0);
reg_buffer[1] = get_register(a1);
- memcpy(x, buffer, sizeof(buffer));
-
+ OS::MemCopy(x, buffer, sizeof(buffer));
// Registers a2 and a3 -> y.
reg_buffer[0] = get_register(a2);
reg_buffer[1] = get_register(a3);
- memcpy(y, buffer, sizeof(buffer));
- }
-}
-
-
-// For use in calls that take one double value, constructed either
-// from a0 and a1 or f12.
-void Simulator::GetFpArgs(double* x) {
- if (!IsMipsSoftFloatABI) {
- *x = get_fpu_register_double(12);
- } else {
- // We use a char buffer to get around the strict-aliasing rules which
- // otherwise allow the compiler to optimize away the copy.
- char buffer[sizeof(*x)];
- int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
- // Registers a0 and a1 -> x.
- reg_buffer[0] = get_register(a0);
- reg_buffer[1] = get_register(a1);
- memcpy(x, buffer, sizeof(buffer));
- }
-}
-
-
-// For use in calls that take one double value constructed either
-// from a0 and a1 or f12 and one integer value.
-void Simulator::GetFpArgs(double* x, int32_t* y) {
- if (!IsMipsSoftFloatABI) {
- *x = get_fpu_register_double(12);
- *y = get_register(a2);
- } else {
- // We use a char buffer to get around the strict-aliasing rules which
- // otherwise allow the compiler to optimize away the copy.
- char buffer[sizeof(*x)];
- int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
- // Registers 0 and 1 -> x.
- reg_buffer[0] = get_register(a0);
- reg_buffer[1] = get_register(a1);
- memcpy(x, buffer, sizeof(buffer));
-
- // Register 2 -> y.
+ OS::MemCopy(y, buffer, sizeof(buffer));
+ // Register 2 -> z.
reg_buffer[0] = get_register(a2);
- memcpy(y, buffer, sizeof(*y));
+ OS::MemCopy(z, buffer, sizeof(*z));
}
}
@@ -1164,7 +1127,7 @@
} else {
char buffer[2 * sizeof(registers_[0])];
int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
- memcpy(buffer, &result, sizeof(buffer));
+ OS::MemCopy(buffer, &result, sizeof(buffer));
// Copy result to v0 and v1.
set_register(v0, reg_buffer[0]);
set_register(v1, reg_buffer[1]);
@@ -1415,10 +1378,12 @@
int32_t arg3,
int32_t arg4,
int32_t arg5);
-typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
- int32_t arg1,
- int32_t arg2,
- int32_t arg3);
+
+// These prototypes handle the four types of FP calls.
+typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPCall)(double darg0);
+typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
@@ -1495,46 +1460,81 @@
// simulator. Soft-float has additional abstraction of ExternalReference,
// to support serialization.
if (fp_call) {
- SimulatorRuntimeFPCall target =
- reinterpret_cast<SimulatorRuntimeFPCall>(external);
+ double dval0, dval1; // one or two double parameters
+ int32_t ival; // zero or one integer parameters
+ int64_t iresult = 0; // integer return value
+ double dresult = 0; // double return value
+ GetFpArgs(&dval0, &dval1, &ival);
+ SimulatorRuntimeCall generic_target =
+ reinterpret_cast<SimulatorRuntimeCall>(external);
if (::v8::internal::FLAG_trace_sim) {
- double dval0, dval1;
- int32_t ival;
switch (redirection->type()) {
case ExternalReference::BUILTIN_FP_FP_CALL:
case ExternalReference::BUILTIN_COMPARE_CALL:
- GetFpArgs(&dval0, &dval1);
PrintF("Call to host function at %p with args %f, %f",
- FUNCTION_ADDR(target), dval0, dval1);
+ FUNCTION_ADDR(generic_target), dval0, dval1);
break;
case ExternalReference::BUILTIN_FP_CALL:
- GetFpArgs(&dval0);
PrintF("Call to host function at %p with arg %f",
- FUNCTION_ADDR(target), dval0);
+ FUNCTION_ADDR(generic_target), dval0);
break;
case ExternalReference::BUILTIN_FP_INT_CALL:
- GetFpArgs(&dval0, &ival);
PrintF("Call to host function at %p with args %f, %d",
- FUNCTION_ADDR(target), dval0, ival);
+ FUNCTION_ADDR(generic_target), dval0, ival);
break;
default:
UNREACHABLE();
break;
}
}
- if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
+ switch (redirection->type()) {
+ case ExternalReference::BUILTIN_COMPARE_CALL: {
+ SimulatorRuntimeCompareCall target =
+ reinterpret_cast<SimulatorRuntimeCompareCall>(external);
+ iresult = target(dval0, dval1);
+ set_register(v0, static_cast<int32_t>(iresult));
+ set_register(v1, static_cast<int32_t>(iresult >> 32));
+ break;
+ }
+ case ExternalReference::BUILTIN_FP_FP_CALL: {
+ SimulatorRuntimeFPFPCall target =
+ reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
+ dresult = target(dval0, dval1);
+ SetFpResult(dresult);
+ break;
+ }
+ case ExternalReference::BUILTIN_FP_CALL: {
SimulatorRuntimeFPCall target =
- reinterpret_cast<SimulatorRuntimeFPCall>(external);
- double result = target(arg0, arg1, arg2, arg3);
- SetFpResult(result);
- } else {
- SimulatorRuntimeCall target =
- reinterpret_cast<SimulatorRuntimeCall>(external);
- uint64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
- int32_t gpreg_pair[2];
- memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
- set_register(v0, gpreg_pair[0]);
- set_register(v1, gpreg_pair[1]);
+ reinterpret_cast<SimulatorRuntimeFPCall>(external);
+ dresult = target(dval0);
+ SetFpResult(dresult);
+ break;
+ }
+ case ExternalReference::BUILTIN_FP_INT_CALL: {
+ SimulatorRuntimeFPIntCall target =
+ reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
+ dresult = target(dval0, ival);
+ SetFpResult(dresult);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ if (::v8::internal::FLAG_trace_sim) {
+ switch (redirection->type()) {
+ case ExternalReference::BUILTIN_COMPARE_CALL:
+ PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
+ break;
+ case ExternalReference::BUILTIN_FP_FP_CALL:
+ case ExternalReference::BUILTIN_FP_CALL:
+ case ExternalReference::BUILTIN_FP_INT_CALL:
+ PrintF("Returned %f\n", dresult);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
} else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
// See DirectCEntryStub::GenerateCall for explanation of register usage.
@@ -2867,9 +2867,9 @@
} else {
int buffer[2];
ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
- memcpy(buffer, &d0, sizeof(d0));
+ OS::MemCopy(buffer, &d0, sizeof(d0));
set_dw_register(a0, buffer);
- memcpy(buffer, &d1, sizeof(d1));
+ OS::MemCopy(buffer, &d1, sizeof(d1));
set_dw_register(a2, buffer);
}
CallInternal(entry);
diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h
index ed63443..a091e5f 100644
--- a/src/mips/simulator-mips.h
+++ b/src/mips/simulator-mips.h
@@ -351,10 +351,8 @@
static void* RedirectExternalReference(void* external_function,
ExternalReference::Type type);
- // For use in calls that take double value arguments.
- void GetFpArgs(double* x, double* y);
- void GetFpArgs(double* x);
- void GetFpArgs(double* x, int32_t* y);
+ // Handle arguments and return value for runtime FP functions.
+ void GetFpArgs(double* x, double* y, int32_t* z);
void SetFpResult(const double& result);
void CallInternal(byte* entry);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index da6770a..b9757fa 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -410,29 +410,46 @@
}
-// Generate StoreField code, value is passed in a0 register.
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+ Handle<GlobalObject> global,
+ Handle<Name> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ __ li(scratch, Operand(cell));
+ __ lw(scratch,
+ FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ Branch(miss, ne, scratch, Operand(at));
+}
+
+
+// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label,
- Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label,
+ Label* miss_restore_name) {
// a0 : value.
Label exit;
// Check that the map of the object hasn't changed.
- CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
- : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK, mode);
+ DO_SMI_CHECK, REQUIRE_EXACT_MAP);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -440,7 +457,7 @@
}
// Check that we are allowed to write this.
- if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+ if (object->GetPrototype()->IsJSObject()) {
JSObject* holder;
// holder == object indicates that no property was found.
if (lookup->holder() != *object) {
@@ -458,12 +475,18 @@
// If no property was found, and the holder (the last object in the
// prototype chain) is in slow mode, we need to do a negative lookup on the
// holder.
- if (lookup->holder() == *object &&
- !holder->HasFastProperties() &&
- !holder->IsJSGlobalProxy() &&
- !holder->IsJSGlobalObject()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ if (lookup->holder() == *object) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm,
+ Handle<GlobalObject>(GlobalObject::cast(holder)),
+ name,
+ scratch1,
+ miss_restore_name);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
}
@@ -472,7 +495,7 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+ if (object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
@@ -485,33 +508,114 @@
return;
}
- int index;
- if (!transition.is_null()) {
- // Update the map of the object.
- __ li(scratch1, Operand(transition));
- __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+ // Update the map of the object.
+ __ li(scratch1, Operand(transition));
+ __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
- // Update the write barrier for the map field and pass the now unused
- // name_reg as scratch register.
- __ RecordWriteField(receiver_reg,
- HeapObject::kMapOffset,
- scratch1,
- name_reg,
- kRAHasNotBeenSaved,
- kDontSaveFPRegs,
- OMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- index = transition->instance_descriptors()->GetFieldIndex(
- transition->LastAdded());
- } else {
- index = lookup->GetFieldIndex().field_index();
- }
+ // Update the write barrier for the map field and pass the now unused
+ // name_reg as scratch register.
+ __ RecordWriteField(receiver_reg,
+ HeapObject::kMapOffset,
+ scratch1,
+ name_reg,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ int index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= object->map()->inobject_properties();
+ // TODO(verwaest): Share this code as a code stub.
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ JumpIfSmi(value_reg, &exit);
+
+ // Update the write barrier for the array address.
+ // Pass the now unused name_reg as a scratch register.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(receiver_reg,
+ offset,
+ name_reg,
+ scratch1,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array
+ __ lw(scratch1,
+ FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ sw(value_reg, FieldMemOperand(scratch1, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ JumpIfSmi(value_reg, &exit);
+
+ // Update the write barrier for the array address.
+ // Ok to clobber receiver_reg and name_reg, since we return.
+ __ mov(name_reg, value_reg);
+ __ RecordWriteField(scratch1,
+ offset,
+ name_reg,
+ receiver_reg,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs);
+ }
+
+ // Return the value (register v0).
+ ASSERT(value_reg.is(a0));
+ __ bind(&exit);
+ __ mov(v0, a0);
+ __ Ret();
+}
+
+
+// Generate StoreField code, value is passed in a0 register.
+// When leaving generated code after success, the receiver_reg and name_reg
+// may be clobbered. Upon branch to miss_label, the receiver and name
+// registers have their original values.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ // a0 : value
+ Label exit;
+
+ // Check that the map of the object hasn't changed.
+ __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
+ DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ int index = lookup->GetFieldIndex().field_index();
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ // TODO(verwaest): Share this code as a code stub.
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -926,26 +1030,6 @@
};
-
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
- Handle<GlobalObject> global,
- Handle<Name> name,
- Register scratch,
- Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
- GlobalObject::EnsurePropertyCell(global, name);
- ASSERT(cell->value()->IsTheHole());
- __ li(scratch, Operand(cell));
- __ lw(scratch,
- FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ Branch(miss, ne, scratch, Operand(at));
-}
-
-
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
@@ -975,72 +1059,12 @@
Register dst,
Register wordoffset,
Register ival,
- Register fval,
- Register scratch1,
- Register scratch2) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ mtc1(ival, f0);
- __ cvt_s_w(f0, f0);
- __ sll(scratch1, wordoffset, 2);
- __ addu(scratch1, dst, scratch1);
- __ swc1(f0, MemOperand(scratch1, 0));
- } else {
- // FPU is not available, do manual conversions.
-
- Label not_special, done;
- // Move sign bit from source to destination. This works because the sign
- // bit in the exponent word of the double has the same position and polarity
- // as the 2's complement sign bit in a Smi.
- ASSERT(kBinary32SignMask == 0x80000000u);
-
- __ And(fval, ival, Operand(kBinary32SignMask));
- // Negate value if it is negative.
- __ subu(scratch1, zero_reg, ival);
- __ Movn(ival, scratch1, fval);
-
- // We have -1, 0 or 1, which we treat specially. Register ival contains
- // absolute value: it is either equal to 1 (special case of -1 and 1),
- // greater than 1 (not a special case) or less than 1 (special case of 0).
- __ Branch(¬_special, gt, ival, Operand(1));
-
- // For 1 or -1 we need to or in the 0 exponent (biased).
- static const uint32_t exponent_word_for_1 =
- kBinary32ExponentBias << kBinary32ExponentShift;
-
- __ Xor(scratch1, ival, Operand(1));
- __ li(scratch2, exponent_word_for_1);
- __ or_(scratch2, fval, scratch2);
- __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
- __ Branch(&done);
-
- __ bind(¬_special);
- // Count leading zeros.
- // Gets the wrong answer for 0, but we already checked for that case above.
- Register zeros = scratch2;
- __ Clz(zeros, ival);
-
- // Compute exponent and or it into the exponent register.
- __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
- __ subu(scratch1, scratch1, zeros);
-
- __ sll(scratch1, scratch1, kBinary32ExponentShift);
- __ or_(fval, fval, scratch1);
-
- // Shift up the source chopping the top bit off.
- __ Addu(zeros, zeros, Operand(1));
- // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
- __ sllv(ival, ival, zeros);
- // And the top (top 20 bits).
- __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
- __ or_(fval, fval, scratch1);
-
- __ bind(&done);
-
- __ sll(scratch1, wordoffset, 2);
- __ addu(scratch1, dst, scratch1);
- __ sw(fval, MemOperand(scratch1, 0));
- }
+ Register scratch1) {
+ __ mtc1(ival, f0);
+ __ cvt_s_w(f0, f0);
+ __ sll(scratch1, wordoffset, 2);
+ __ addu(scratch1, dst, scratch1);
+ __ swc1(f0, MemOperand(scratch1, 0));
}
@@ -1229,7 +1253,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+ HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1237,13 +1261,6 @@
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- if (!last->HasFastProperties()) {
- __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
- __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
- __ Branch(&miss, ne, scratch2(),
- Operand(isolate()->factory()->null_value()));
- }
-
HandlerFrontendFooter(success, &miss);
}
@@ -2100,11 +2117,7 @@
// -- sp[argc * 4] : receiver
// -----------------------------------
- if (!CpuFeatures::IsSupported(FPU)) {
- return Handle<Code>::null();
- }
- CpuFeatureScope scope_fpu(masm(), FPU);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
@@ -3170,36 +3183,6 @@
}
-static bool IsElementTypeSigned(ElementsKind elements_kind) {
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- return true;
-
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_PIXEL_ELEMENTS:
- return false;
-
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- return false;
- }
- return false;
-}
-
-
static void GenerateSmiKeyCheck(MacroAssembler* masm,
Register key,
Register scratch0,
@@ -3207,36 +3190,30 @@
FPURegister double_scratch0,
FPURegister double_scratch1,
Label* fail) {
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- Label key_ok;
- // Check for smi or a smi inside a heap number. We convert the heap
- // number and check if the conversion is exact and fits into the smi
- // range.
- __ JumpIfSmi(key, &key_ok);
- __ CheckMap(key,
- scratch0,
- Heap::kHeapNumberMapRootIndex,
- fail,
- DONT_DO_SMI_CHECK);
- __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
- __ EmitFPUTruncate(kRoundToZero,
- scratch0,
- double_scratch0,
- at,
- double_scratch1,
- scratch1,
- kCheckForInexactConversion);
+ Label key_ok;
+ // Check for smi or a smi inside a heap number. We convert the heap
+ // number and check if the conversion is exact and fits into the smi
+ // range.
+ __ JumpIfSmi(key, &key_ok);
+ __ CheckMap(key,
+ scratch0,
+ Heap::kHeapNumberMapRootIndex,
+ fail,
+ DONT_DO_SMI_CHECK);
+ __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
+ __ EmitFPUTruncate(kRoundToZero,
+ scratch0,
+ double_scratch0,
+ at,
+ double_scratch1,
+ scratch1,
+ kCheckForInexactConversion);
- __ Branch(fail, ne, scratch1, Operand(zero_reg));
+ __ Branch(fail, ne, scratch1, Operand(zero_reg));
- __ SmiTagCheckOverflow(key, scratch0, scratch1);
- __ BranchOnOverflow(fail, scratch1);
- __ bind(&key_ok);
- } else {
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, fail);
- }
+ __ SmiTagCheckOverflow(key, scratch0, scratch1);
+ __ BranchOnOverflow(fail, scratch1);
+ __ bind(&key_ok);
}
@@ -3327,29 +3304,19 @@
case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(t0, key);
- StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
+ StoreIntAsFloat(masm, a3, t0, t1, t2);
break;
case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t8, key, 2);
__ addu(a3, a3, t8);
// a3: effective address of the double element
FloatingPointHelper::Destination destination;
- if (CpuFeatures::IsSupported(FPU)) {
- destination = FloatingPointHelper::kFPURegisters;
- } else {
- destination = FloatingPointHelper::kCoreRegisters;
- }
+ destination = FloatingPointHelper::kFPURegisters;
FloatingPointHelper::ConvertIntToDouble(
masm, t1, destination,
f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
t0, f2); // These are: scratch2, single_scratch.
- if (destination == FloatingPointHelper::kFPURegisters) {
- CpuFeatureScope scope(masm, FPU);
- __ sdc1(f0, MemOperand(a3, 0));
- } else {
- __ sw(t2, MemOperand(a3, 0));
- __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
- }
+ __ sdc1(f0, MemOperand(a3, 0));
break;
case FAST_ELEMENTS:
case FAST_SMI_ELEMENTS:
@@ -3381,232 +3348,59 @@
// +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero.
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatureScope scope(masm, FPU);
- __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
+ __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- __ cvt_s_d(f0, f0);
- __ sll(t8, key, 1);
- __ addu(t8, a3, t8);
- __ swc1(f0, MemOperand(t8, 0));
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- __ sll(t8, key, 2);
- __ addu(t8, a3, t8);
- __ sdc1(f0, MemOperand(t8, 0));
- } else {
- __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
-
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ srl(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sb(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ addu(t8, a3, key);
- __ sh(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ sll(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sw(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
- }
-
- // Entry registers are intact, a0 holds the value
- // which is the return value.
- __ mov(v0, a0);
- __ Ret();
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+ __ cvt_s_d(f0, f0);
+ __ sll(t8, key, 1);
+ __ addu(t8, a3, t8);
+ __ swc1(f0, MemOperand(t8, 0));
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+ __ sll(t8, key, 2);
+ __ addu(t8, a3, t8);
+ __ sdc1(f0, MemOperand(t8, 0));
} else {
- // FPU is not available, do manual conversions.
+ __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
- __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
- __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
-
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- Label done, nan_or_infinity_or_zero;
- static const int kMantissaInHiWordShift =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaInLoWordShift =
- kBitsPerInt - kMantissaInHiWordShift;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ li(t5, HeapNumber::kExponentMask);
- __ and_(t6, t3, t5);
- __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
-
- __ xor_(t1, t6, t5);
- __ li(t2, kBinary32ExponentMask);
- __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
- __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
-
- // Rebias exponent.
- __ srl(t6, t6, HeapNumber::kExponentShift);
- __ Addu(t6,
- t6,
- Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
-
- __ li(t1, Operand(kBinary32MaxExponent));
- __ Slt(t1, t1, t6);
- __ And(t2, t3, Operand(HeapNumber::kSignMask));
- __ Or(t2, t2, Operand(kBinary32ExponentMask));
- __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
- __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
-
- __ Slt(t1, t6, Operand(kBinary32MinExponent));
- __ And(t2, t3, Operand(HeapNumber::kSignMask));
- __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
- __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
-
- __ And(t7, t3, Operand(HeapNumber::kSignMask));
- __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
- __ sll(t3, t3, kMantissaInHiWordShift);
- __ or_(t7, t7, t3);
- __ srl(t4, t4, kMantissaInLoWordShift);
- __ or_(t7, t7, t4);
- __ sll(t6, t6, kBinary32ExponentShift);
- __ or_(t3, t7, t6);
-
- __ bind(&done);
- __ sll(t9, key, 1);
- __ addu(t9, a3, t9);
- __ sw(t3, MemOperand(t9, 0));
-
- // Entry registers are intact, a0 holds the value which is the return
- // value.
- __ mov(v0, a0);
- __ Ret();
-
- __ bind(&nan_or_infinity_or_zero);
- __ And(t7, t3, Operand(HeapNumber::kSignMask));
- __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
- __ or_(t6, t6, t7);
- __ sll(t3, t3, kMantissaInHiWordShift);
- __ or_(t6, t6, t3);
- __ srl(t4, t4, kMantissaInLoWordShift);
- __ or_(t3, t6, t4);
- __ Branch(&done);
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- __ sll(t8, key, 2);
- __ addu(t8, a3, t8);
- // t8: effective address of destination element.
- __ sw(t4, MemOperand(t8, 0));
- __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
- __ mov(v0, a0);
- __ Ret();
- } else {
- bool is_signed_type = IsElementTypeSigned(elements_kind);
- int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
- int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
-
- Label done, sign;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ li(t5, HeapNumber::kExponentMask);
- __ and_(t6, t3, t5);
- __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
- __ Branch(&done, eq, t6, Operand(zero_reg));
-
- __ xor_(t2, t6, t5);
- __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
- __ Branch(&done, eq, t6, Operand(t5));
-
- // Unbias exponent.
- __ srl(t6, t6, HeapNumber::kExponentShift);
- __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
- // If exponent is negative then result is 0.
- __ slt(t2, t6, zero_reg);
- __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
- __ Branch(&done, lt, t6, Operand(zero_reg));
-
- // If exponent is too big then result is minimal value.
- __ slti(t1, t6, meaningfull_bits - 1);
- __ li(t2, min_value);
- __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
- __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
-
- __ And(t5, t3, Operand(HeapNumber::kSignMask));
- __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
- __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
-
- __ li(t9, HeapNumber::kMantissaBitsInTopWord);
- __ subu(t6, t9, t6);
- __ slt(t1, t6, zero_reg);
- __ srlv(t2, t3, t6);
- __ Movz(t3, t2, t1); // Only if t6 is positive.
- __ Branch(&sign, ge, t6, Operand(zero_reg));
-
- __ subu(t6, zero_reg, t6);
- __ sllv(t3, t3, t6);
- __ li(t9, meaningfull_bits);
- __ subu(t6, t9, t6);
- __ srlv(t4, t4, t6);
- __ or_(t3, t3, t4);
-
- __ bind(&sign);
- __ subu(t2, t3, zero_reg);
- __ Movz(t3, t2, t5); // Only if t5 is zero.
-
- __ bind(&done);
-
- // Result is in t3.
- // This switch block should be exactly the same as above (FPU mode).
- switch (elements_kind) {
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ srl(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sb(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ addu(t8, a3, key);
- __ sh(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ sll(t8, key, 1);
- __ addu(t8, a3, t8);
- __ sw(t3, MemOperand(t8, 0));
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_SMI_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
+ switch (elements_kind) {
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ __ srl(t8, key, 1);
+ __ addu(t8, a3, t8);
+ __ sb(t3, MemOperand(t8, 0));
+ break;
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ __ addu(t8, a3, key);
+ __ sh(t3, MemOperand(t8, 0));
+ break;
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ __ sll(t8, key, 1);
+ __ addu(t8, a3, t8);
+ __ sw(t3, MemOperand(t8, 0));
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
+ break;
}
}
+
+ // Entry registers are intact, a0 holds the value
+ // which is the return value.
+ __ mov(v0, a0);
+ __ Ret();
}
// Slow case, key and receiver still in a0 and a1.
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 44cab53..24730a0 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -139,6 +139,9 @@
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
JSObject::cast(this)->JSObjectVerify();
break;
+ case JS_GENERATOR_OBJECT_TYPE:
+ JSGeneratorObject::cast(this)->JSGeneratorObjectVerify();
+ break;
case JS_MODULE_TYPE:
JSModule::cast(this)->JSModuleVerify();
break;
@@ -198,6 +201,9 @@
case JS_ARRAY_BUFFER_TYPE:
JSArrayBuffer::cast(this)->JSArrayBufferVerify();
break;
+ case JS_TYPED_ARRAY_TYPE:
+ JSTypedArray::cast(this)->JSTypedArrayVerify();
+ break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
@@ -404,6 +410,17 @@
}
+void JSGeneratorObject::JSGeneratorObjectVerify() {
+ // In an expression like "new g()", there can be a point where a generator
+ // object is allocated but its fields are all undefined, as it hasn't yet been
+ // initialized by the generator. Hence these weak checks.
+ VerifyObjectField(kFunctionOffset);
+ VerifyObjectField(kContextOffset);
+ VerifyObjectField(kOperandStackOffset);
+ VerifyObjectField(kContinuationOffset);
+}
+
+
void JSModule::JSModuleVerify() {
VerifyObjectField(kContextOffset);
VerifyObjectField(kScopeInfoOffset);
@@ -724,6 +741,28 @@
}
+void JSTypedArray::JSTypedArrayVerify() {
+ CHECK(IsJSTypedArray());
+ JSObjectVerify();
+ VerifyPointer(buffer());
+ CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined());
+
+ VerifyPointer(byte_offset());
+ CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber()
+ || byte_offset()->IsUndefined());
+
+ VerifyPointer(byte_length());
+ CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber()
+ || byte_length()->IsUndefined());
+
+ VerifyPointer(length());
+ CHECK(length()->IsSmi() || length()->IsHeapNumber()
+ || length()->IsUndefined());
+
+ VerifyPointer(elements());
+}
+
+
void Foreign::ForeignVerify() {
CHECK(IsForeign());
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index ec03405..efc1764 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -653,6 +653,7 @@
TYPE_CHECKER(Oddball, ODDBALL_TYPE)
TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE)
TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
+TYPE_CHECKER(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE)
TYPE_CHECKER(JSModule, JS_MODULE_TYPE)
TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
TYPE_CHECKER(JSDate, JS_DATE_TYPE)
@@ -675,6 +676,7 @@
TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE)
+TYPE_CHECKER(JSTypedArray, JS_TYPED_ARRAY_TYPE)
TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
@@ -1488,22 +1490,59 @@
}
-bool JSObject::TryTransitionToField(Handle<JSObject> object,
- Handle<Name> key) {
- if (!object->map()->HasTransitionArray()) return false;
- Handle<Map> target;
- {
- AssertNoAllocation no_allocation;
- TransitionArray* transitions = object->map()->transitions();
- int transition = transitions->Search(*key);
- if (transition == TransitionArray::kNotFound) return false;
- PropertyDetails target_details = transitions->GetTargetDetails(transition);
- if (target_details.type() != FIELD) return false;
- if (target_details.attributes() != NONE) return false;
- target = Handle<Map>(transitions->GetTarget(transition));
+MaybeObject* JSObject::TransitionToMap(Map* map) {
+ ASSERT(this->map()->inobject_properties() == map->inobject_properties());
+ ElementsKind expected_kind = this->map()->elements_kind();
+ if (map->elements_kind() != expected_kind) {
+ MaybeObject* maybe_map = map->AsElementsKind(expected_kind);
+ if (!maybe_map->To(&map)) return maybe_map;
}
- JSObject::AddFastPropertyUsingMap(object, target);
- return true;
+ int total_size =
+ map->NumberOfOwnDescriptors() + map->unused_property_fields();
+ int out_of_object = total_size - map->inobject_properties();
+ if (out_of_object != properties()->length()) {
+ FixedArray* new_properties;
+ MaybeObject* maybe_properties = properties()->CopySize(out_of_object);
+ if (!maybe_properties->To(&new_properties)) return maybe_properties;
+ set_properties(new_properties);
+ }
+ set_map(map);
+ return this;
+}
+
+
+Handle<String> JSObject::ExpectedTransitionKey(Handle<Map> map) {
+ AssertNoAllocation no_gc;
+ if (!map->HasTransitionArray()) return Handle<String>::null();
+ TransitionArray* transitions = map->transitions();
+ if (!transitions->IsSimpleTransition()) return Handle<String>::null();
+ int transition = TransitionArray::kSimpleTransitionIndex;
+ PropertyDetails details = transitions->GetTargetDetails(transition);
+ Name* name = transitions->GetKey(transition);
+ if (details.type() != FIELD) return Handle<String>::null();
+ if (details.attributes() != NONE) return Handle<String>::null();
+ if (!name->IsString()) return Handle<String>::null();
+ return Handle<String>(String::cast(name));
+}
+
+
+Handle<Map> JSObject::ExpectedTransitionTarget(Handle<Map> map) {
+ ASSERT(!ExpectedTransitionKey(map).is_null());
+ return Handle<Map>(map->transitions()->GetTarget(
+ TransitionArray::kSimpleTransitionIndex));
+}
+
+
+Handle<Map> JSObject::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
+ AssertNoAllocation no_allocation;
+ if (!map->HasTransitionArray()) return Handle<Map>::null();
+ TransitionArray* transitions = map->transitions();
+ int transition = transitions->Search(*key);
+ if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
+ PropertyDetails target_details = transitions->GetTargetDetails(transition);
+ if (target_details.type() != FIELD) return Handle<Map>::null();
+ if (target_details.attributes() != NONE) return Handle<Map>::null();
+ return Handle<Map>(transitions->GetTarget(transition));
}
@@ -1547,6 +1586,8 @@
// field operations considerably on average.
if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
switch (type) {
+ case JS_GENERATOR_OBJECT_TYPE:
+ return JSGeneratorObject::kSize;
case JS_MODULE_TYPE:
return JSModule::kSize;
case JS_GLOBAL_PROXY_TYPE:
@@ -1565,6 +1606,8 @@
return JSArray::kSize;
case JS_ARRAY_BUFFER_TYPE:
return JSArrayBuffer::kSize;
+ case JS_TYPED_ARRAY_TYPE:
+ return JSTypedArray::kSize;
case JS_SET_TYPE:
return JSSet::kSize;
case JS_MAP_TYPE:
@@ -2452,6 +2495,7 @@
CAST_ACCESSOR(Code)
CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSArrayBuffer)
+CAST_ACCESSOR(JSTypedArray)
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSFunctionProxy)
@@ -2508,8 +2552,8 @@
bool Name::Equals(Name* other) {
if (other == this) return true;
- if (this->IsSymbol() || other->IsSymbol() ||
- (this->IsInternalizedString() && other->IsInternalizedString())) {
+ if ((this->IsInternalizedString() && other->IsInternalizedString()) ||
+ this->IsSymbol() || other->IsSymbol()) {
return false;
}
return String::cast(this)->SlowEquals(String::cast(other));
@@ -3762,33 +3806,33 @@
}
-unsigned Code::stack_check_table_offset() {
+unsigned Code::back_edge_table_offset() {
ASSERT_EQ(FUNCTION, kind());
- return StackCheckTableOffsetField::decode(
+ return BackEdgeTableOffsetField::decode(
READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
}
-void Code::set_stack_check_table_offset(unsigned offset) {
+void Code::set_back_edge_table_offset(unsigned offset) {
ASSERT_EQ(FUNCTION, kind());
ASSERT(IsAligned(offset, static_cast<unsigned>(kIntSize)));
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
- int updated = StackCheckTableOffsetField::update(previous, offset);
+ int updated = BackEdgeTableOffsetField::update(previous, offset);
WRITE_UINT32_FIELD(this, kKindSpecificFlags2Offset, updated);
}
-bool Code::stack_check_patched_for_osr() {
+bool Code::back_edges_patched_for_osr() {
ASSERT_EQ(FUNCTION, kind());
- return StackCheckPatchedForOSRField::decode(
+ return BackEdgesPatchedForOSRField::decode(
READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
}
-void Code::set_stack_check_patched_for_osr(bool value) {
+void Code::set_back_edges_patched_for_osr(bool value) {
ASSERT_EQ(FUNCTION, kind());
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
- int updated = StackCheckPatchedForOSRField::update(previous, value);
+ int updated = BackEdgesPatchedForOSRField::update(previous, value);
WRITE_UINT32_FIELD(this, kKindSpecificFlags2Offset, updated);
}
@@ -4973,6 +5017,19 @@
}
+ACCESSORS(JSGeneratorObject, function, JSFunction, kFunctionOffset)
+ACCESSORS(JSGeneratorObject, context, Object, kContextOffset)
+SMI_ACCESSORS(JSGeneratorObject, continuation, kContinuationOffset)
+ACCESSORS(JSGeneratorObject, operand_stack, FixedArray, kOperandStackOffset)
+
+
+JSGeneratorObject* JSGeneratorObject::cast(Object* obj) {
+ ASSERT(obj->IsJSGeneratorObject());
+ ASSERT(HeapObject::cast(obj)->Size() == JSGeneratorObject::kSize);
+ return reinterpret_cast<JSGeneratorObject*>(obj);
+}
+
+
ACCESSORS(JSModule, context, Object, kContextOffset)
ACCESSORS(JSModule, scope_info, ScopeInfo, kScopeInfoOffset)
@@ -5154,6 +5211,12 @@
ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset)
+ACCESSORS(JSTypedArray, buffer, Object, kBufferOffset)
+ACCESSORS(JSTypedArray, byte_offset, Object, kByteOffsetOffset)
+ACCESSORS(JSTypedArray, byte_length, Object, kByteLengthOffset)
+ACCESSORS(JSTypedArray, length, Object, kLengthOffset)
+
+
ACCESSORS(JSRegExp, data, Object, kDataOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 8342232..aa71a96 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -132,6 +132,7 @@
case JS_OBJECT_TYPE: // fall through
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_ARRAY_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
case JS_REGEXP_TYPE:
JSObject::cast(this)->JSObjectPrint(out);
break;
@@ -186,6 +187,8 @@
break;
case JS_ARRAY_BUFFER_TYPE:
JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
+ case JS_TYPED_ARRAY_TYPE:
+ JSTypedArray::cast(this)->JSTypedArrayPrint(out);
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
Name::cast(this)->Name##Print(out); \
@@ -530,6 +533,7 @@
case ODDBALL_TYPE: return "ODDBALL";
case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL";
case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO";
+ case JS_GENERATOR_OBJECT_TYPE: return "JS_GENERATOR_OBJECT";
case JS_MODULE_TYPE: return "JS_MODULE";
case JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE";
@@ -807,6 +811,22 @@
}
+void JSTypedArray::JSTypedArrayPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSTypedArray");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - buffer =");
+ buffer()->ShortPrint(out);
+ PrintF(out, "\n - byte_offset = ");
+ byte_offset()->ShortPrint(out);
+ PrintF(out, "\n - byte_length = ");
+ byte_length()->ShortPrint(out);
+ PrintF(out, " - length = ");
+ length()->ShortPrint(out);
+ PrintF("\n");
+ PrintElements(out);
+}
+
+
void JSFunction::JSFunctionPrint(FILE* out) {
HeapObject::PrintHeader(out, "Function");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index fa53562..7b5c8be 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -136,6 +136,7 @@
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
@@ -145,6 +146,7 @@
case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE:
+ case JS_TYPED_ARRAY_TYPE:
return GetVisitorIdForSize(kVisitJSObject,
kVisitJSObjectGeneric,
instance_size);
diff --git a/src/objects.cc b/src/objects.cc
index 8f03b10..33be173 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1290,6 +1290,10 @@
}
break;
}
+ case JS_GENERATOR_OBJECT_TYPE: {
+ accumulator->Add("<JS Generator>");
+ break;
+ }
case JS_MODULE_TYPE: {
accumulator->Add("<JS Module>");
break;
@@ -1546,11 +1550,13 @@
break;
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
case JS_ARRAY_BUFFER_TYPE:
+ case JS_TYPED_ARRAY_TYPE:
case JS_SET_TYPE:
case JS_MAP_TYPE:
case JS_WEAK_MAP_TYPE:
@@ -2602,13 +2608,18 @@
return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
}
- Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
+ return start_map->AsElementsKind(to_kind);
+}
- if (closest_map->elements_kind() == to_kind) {
+
+MaybeObject* Map::AsElementsKind(ElementsKind kind) {
+ Map* closest_map = FindClosestElementsTransition(this, kind);
+
+ if (closest_map->elements_kind() == kind) {
return closest_map;
}
- return AddMissingElementsTransitions(closest_map, to_kind);
+ return AddMissingElementsTransitions(closest_map, kind);
}
@@ -3073,6 +3084,13 @@
}
+void JSObject::TransitionToMap(Handle<JSObject> object, Handle<Map> map) {
+ CALL_HEAP_FUNCTION_VOID(
+ object->GetIsolate(),
+ object->TransitionToMap(*map));
+}
+
+
MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
Name* name_raw,
Object* value_raw,
@@ -7991,7 +8009,7 @@
void String::PrintOn(FILE* file) {
int length = this->length();
for (int i = 0; i < length; i++) {
- fprintf(file, "%c", Get(i));
+ PrintF(file, "%c", Get(i));
}
}
@@ -8546,6 +8564,7 @@
// Check the basic conditions for generating inline constructor code.
if (!FLAG_inline_new
|| !has_only_simple_this_property_assignments()
+ || is_generator()
|| this_property_assignments_count() == 0) {
return false;
}
@@ -9097,13 +9116,6 @@
}
-void Code::SetNoStackCheckTable() {
- // Indicate the absence of a stack-check table by a table start after the
- // end of the instructions. Table start must be aligned, so round up.
- set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
-}
-
-
Map* Code::FindFirstMap() {
ASSERT(is_inline_cache_stub());
AssertNoAllocation no_allocation;
@@ -9622,18 +9634,20 @@
}
PrintF(out, "\n");
} else if (kind() == FUNCTION) {
- unsigned offset = stack_check_table_offset();
- // If there is no stack check table, the "table start" will at or after
+ unsigned offset = back_edge_table_offset();
+ // If there is no back edge table, the "table start" will be at or after
// (due to alignment) the end of the instruction stream.
if (static_cast<int>(offset) < instruction_size()) {
- unsigned* address =
- reinterpret_cast<unsigned*>(instruction_start() + offset);
- unsigned length = address[0];
- PrintF(out, "Stack checks (size = %u)\n", length);
- PrintF(out, "ast_id pc_offset\n");
- for (unsigned i = 0; i < length; ++i) {
- unsigned index = (2 * i) + 1;
- PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
+ Address back_edge_cursor = instruction_start() + offset;
+ uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+ PrintF(out, "Back edges (size = %u)\n", table_length);
+ PrintF(out, "ast_id pc_offset loop_depth\n");
+ for (uint32_t i = 0; i < table_length; ++i) {
+ uint32_t ast_id = Memory::uint32_at(back_edge_cursor);
+ uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+ uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+ PrintF(out, "%6u %9u %10u\n", ast_id, pc_offset, loop_depth);
+ back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
PrintF(out, "\n");
}
@@ -11545,9 +11559,8 @@
}
-bool JSObject::HasRealNamedProperty(Name* key) {
+bool JSObject::HasRealNamedProperty(Isolate* isolate, Name* key) {
// Check access rights if needed.
- Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded()) {
if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
@@ -11561,73 +11574,21 @@
}
-bool JSObject::HasRealElementProperty(uint32_t index) {
+bool JSObject::HasRealElementProperty(Isolate* isolate, uint32_t index) {
// Check access rights if needed.
if (IsAccessCheckNeeded()) {
- Heap* heap = GetHeap();
- if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
- heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
}
- // Handle [] on String objects.
- if (this->IsStringObjectWithCharacterAt(index)) return true;
-
- switch (GetElementsKind()) {
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS: {
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>(
- Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedArray::cast(elements())->length());
- return (index < length) &&
- !FixedArray::cast(elements())->get(index)->IsTheHole();
- }
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS: {
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>(
- Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
- return (index < length) &&
- !FixedDoubleArray::cast(elements())->is_the_hole(index);
- break;
- }
- case EXTERNAL_PIXEL_ELEMENTS: {
- ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
- return index < static_cast<uint32_t>(pixels->length());
- }
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS: {
- ExternalArray* array = ExternalArray::cast(elements());
- return index < static_cast<uint32_t>(array->length());
- }
- case DICTIONARY_ELEMENTS: {
- return element_dictionary()->FindEntry(index)
- != SeededNumberDictionary::kNotFound;
- }
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- }
- // All possibilities have been handled above already.
- UNREACHABLE();
- return GetHeap()->null_value();
+ return GetElementAttributeWithoutInterceptor(this, index, false) != ABSENT;
}
-bool JSObject::HasRealNamedCallbackProperty(Name* key) {
+bool JSObject::HasRealNamedCallbackProperty(Isolate* isolate, Name* key) {
// Check access rights if needed.
- Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded()) {
if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
@@ -14128,7 +14089,7 @@
if (previous_length != 0) {
uint8_t* previous_array =
previous->serialized_data()->GetDataStartAddress();
- memcpy(array, previous_array, previous_length);
+ OS::MemCopy(array, previous_array, previous_length);
array += previous_length;
}
ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
diff --git a/src/objects.h b/src/objects.h
index 37be25f..898b176 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -57,11 +57,13 @@
// - JSObject
// - JSArray
// - JSArrayBuffer
+// - JSTypedArray
// - JSSet
// - JSMap
// - JSWeakMap
// - JSRegExp
// - JSFunction
+// - JSGeneratorObject
// - JSModule
// - GlobalObject
// - JSGlobalObject
@@ -395,12 +397,14 @@
V(JS_DATE_TYPE) \
V(JS_OBJECT_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
+ V(JS_GENERATOR_OBJECT_TYPE) \
V(JS_MODULE_TYPE) \
V(JS_GLOBAL_OBJECT_TYPE) \
V(JS_BUILTINS_OBJECT_TYPE) \
V(JS_GLOBAL_PROXY_TYPE) \
V(JS_ARRAY_TYPE) \
V(JS_ARRAY_BUFFER_TYPE) \
+ V(JS_TYPED_ARRAY_TYPE) \
V(JS_PROXY_TYPE) \
V(JS_WEAK_MAP_TYPE) \
V(JS_REGEXP_TYPE) \
@@ -726,12 +730,14 @@
JS_DATE_TYPE,
JS_OBJECT_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
+ JS_GENERATOR_OBJECT_TYPE,
JS_MODULE_TYPE,
JS_GLOBAL_OBJECT_TYPE,
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE,
JS_ARRAY_BUFFER_TYPE,
+ JS_TYPED_ARRAY_TYPE,
JS_SET_TYPE,
JS_MAP_TYPE,
JS_WEAK_MAP_TYPE,
@@ -953,13 +959,14 @@
V(JSReceiver) \
V(JSObject) \
V(JSContextExtensionObject) \
+ V(JSGeneratorObject) \
V(JSModule) \
V(Map) \
V(DescriptorArray) \
V(TransitionArray) \
V(DeoptimizationInputData) \
V(DeoptimizationOutputData) \
- V(DependentCode) \
+ V(DependentCode) \
V(TypeFeedbackCells) \
V(FixedArray) \
V(FixedDoubleArray) \
@@ -978,6 +985,7 @@
V(Boolean) \
V(JSArray) \
V(JSArrayBuffer) \
+ V(JSTypedArray) \
V(JSProxy) \
V(JSFunctionProxy) \
V(JSSet) \
@@ -1495,6 +1503,8 @@
static const int kExponentBits = 11;
static const int kExponentBias = 1023;
static const int kExponentShift = 20;
+ static const int kInfinityOrNanExponent =
+ (kExponentMask >> kExponentShift) - kExponentBias;
static const int kMantissaBitsInTopWord = 20;
static const int kNonMantissaBitsInTopWord = 12;
@@ -1768,10 +1778,13 @@
Handle<Object> value,
PropertyAttributes attributes);
+ static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
+ static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
+
// Try to follow an existing transition to a field with attributes NONE. The
// return value indicates whether the transition was successful.
- static inline bool TryTransitionToField(Handle<JSObject> object,
- Handle<Name> key);
+ static inline Handle<Map> FindTransitionToField(Handle<Map> map,
+ Handle<Name> key);
inline int LastAddedFieldIndex();
@@ -1779,6 +1792,8 @@
// passed map. This also extends the property backing store if necessary.
static void AddFastPropertyUsingMap(Handle<JSObject> object, Handle<Map> map);
inline MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* map);
+ static void TransitionToMap(Handle<JSObject> object, Handle<Map> map);
+ inline MUST_USE_RESULT MaybeObject* TransitionToMap(Map* map);
// Can cause GC.
MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
@@ -2034,9 +2049,9 @@
inline bool HasIndexedInterceptor();
// Support functions for v8 api (needed for correct interceptor behavior).
- bool HasRealNamedProperty(Name* key);
- bool HasRealElementProperty(uint32_t index);
- bool HasRealNamedCallbackProperty(Name* key);
+ bool HasRealNamedProperty(Isolate* isolate, Name* key);
+ bool HasRealElementProperty(Isolate* isolate, uint32_t index);
+ bool HasRealNamedCallbackProperty(Isolate* isolate, Name* key);
// Get the header size for a JSObject. Used to compute the index of
// internal fields as well as the number of internal fields.
@@ -4501,13 +4516,13 @@
inline unsigned safepoint_table_offset();
inline void set_safepoint_table_offset(unsigned offset);
- // [stack_check_table_start]: For kind FUNCTION, the offset in the
- // instruction stream where the stack check table starts.
- inline unsigned stack_check_table_offset();
- inline void set_stack_check_table_offset(unsigned offset);
+ // [back_edge_table_start]: For kind FUNCTION, the offset in the
+ // instruction stream where the back edge table starts.
+ inline unsigned back_edge_table_offset();
+ inline void set_back_edge_table_offset(unsigned offset);
- inline bool stack_check_patched_for_osr();
- inline void set_stack_check_patched_for_osr(bool value);
+ inline bool back_edges_patched_for_osr();
+ inline void set_back_edges_patched_for_osr(bool value);
// [check type]: For kind CALL_IC, tells how to check if the
// receiver is valid for the given call.
@@ -4538,10 +4553,6 @@
// Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc);
- // Mark this code object as not having a stack check table. Assumes kind
- // is FUNCTION.
- void SetNoStackCheckTable();
-
// Find the first map in an IC stub.
Map* FindFirstMap();
void FindAllMaps(MapHandleList* maps);
@@ -4791,8 +4802,8 @@
kStubMajorKeyFirstBit, kStubMajorKeyBits> {}; // NOLINT
// KindSpecificFlags2 layout (FUNCTION)
- class StackCheckTableOffsetField: public BitField<int, 0, 31> {};
- class StackCheckPatchedForOSRField: public BitField<bool, 31, 1> {};
+ class BackEdgeTableOffsetField: public BitField<int, 0, 31> {};
+ class BackEdgesPatchedForOSRField: public BitField<bool, 31, 1> {};
// Signed field cannot be encoded using the BitField class.
static const int kArgumentsCountShift = 17;
@@ -5242,6 +5253,7 @@
Descriptor* descriptor,
int index,
TransitionFlag flag);
+ MUST_USE_RESULT MaybeObject* AsElementsKind(ElementsKind kind);
MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
TransitionFlag flag);
@@ -6251,6 +6263,40 @@
};
+class JSGeneratorObject: public JSObject {
+ public:
+ // [function]: The function corresponding to this generator object.
+ DECL_ACCESSORS(function, JSFunction)
+
+ // [context]: The context of the suspended computation, or undefined.
+ DECL_ACCESSORS(context, Object)
+
+ // [continuation]: Offset into code of continuation.
+ inline int continuation();
+ inline void set_continuation(int continuation);
+
+ // [operands]: Saved operand stack.
+ DECL_ACCESSORS(operand_stack, FixedArray)
+
+ // Casting.
+ static inline JSGeneratorObject* cast(Object* obj);
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSGeneratorObject)
+ DECLARE_VERIFIER(JSGeneratorObject)
+
+ // Layout description.
+ static const int kFunctionOffset = JSObject::kHeaderSize;
+ static const int kContextOffset = kFunctionOffset + kPointerSize;
+ static const int kContinuationOffset = kContextOffset + kPointerSize;
+ static const int kOperandStackOffset = kContinuationOffset + kPointerSize;
+ static const int kSize = kOperandStackOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSGeneratorObject);
+};
+
+
// Representation for module instance objects.
class JSModule: public JSObject {
public:
@@ -8517,6 +8563,38 @@
};
+class JSTypedArray: public JSObject {
+ public:
+ // [buffer]: ArrayBuffer that this typed array views.
+ DECL_ACCESSORS(buffer, Object)
+
+ // [byte_length]: offset of typed array in bytes.
+ DECL_ACCESSORS(byte_offset, Object)
+
+ // [byte_length]: length of typed array in bytes.
+ DECL_ACCESSORS(byte_length, Object)
+
+ // [length]: length of typed array in elements.
+ DECL_ACCESSORS(length, Object)
+
+ // Casting.
+ static inline JSTypedArray* cast(Object* obj);
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSTypedArray)
+ DECLARE_VERIFIER(JSTypedArray)
+
+ static const int kBufferOffset = JSObject::kHeaderSize;
+ static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
+ static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
+ static const int kLengthOffset = kByteLengthOffset + kPointerSize;
+ static const int kSize = kLengthOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
+};
+
+
// 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.
diff --git a/src/parser.cc b/src/parser.cc
index d1228d2..b4ab623 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -486,14 +486,13 @@
Parser::FunctionState::FunctionState(Parser* parser,
Scope* scope,
- bool is_generator,
Isolate* isolate)
: next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
next_handler_index_(0),
expected_property_count_(0),
- is_generator_(is_generator),
only_simple_this_property_assignments_(false),
this_property_assignments_(isolate->factory()->empty_fixed_array()),
+ generator_object_variable_(NULL),
parser_(parser),
outer_function_state_(parser->current_function_state_),
outer_scope_(parser->top_scope_),
@@ -537,36 +536,32 @@
// ----------------------------------------------------------------------------
// Implementation of Parser
-Parser::Parser(CompilationInfo* info,
- int parser_flags,
- v8::Extension* extension,
- ScriptDataImpl* pre_data)
+Parser::Parser(CompilationInfo* info)
: isolate_(info->isolate()),
- symbol_cache_(pre_data ? pre_data->symbol_count() : 0, info->zone()),
+ symbol_cache_(0, info->zone()),
script_(info->script()),
scanner_(isolate_->unicode_cache()),
reusable_preparser_(NULL),
top_scope_(NULL),
current_function_state_(NULL),
target_stack_(NULL),
- extension_(extension),
- pre_data_(pre_data),
+ extension_(info->extension()),
+ pre_parse_data_(NULL),
fni_(NULL),
- allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0),
- allow_lazy_((parser_flags & kAllowLazy) != 0),
- allow_modules_((parser_flags & kAllowModules) != 0),
+ allow_natives_syntax_(false),
+ allow_lazy_(false),
+ allow_generators_(false),
stack_overflow_(false),
parenthesized_function_(false),
zone_(info->zone()),
info_(info) {
ASSERT(!script_.is_null());
isolate_->set_ast_node_id(0);
- if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
- scanner().SetHarmonyScoping(true);
- }
- if ((parser_flags & kAllowModules) != 0) {
- scanner().SetHarmonyModules(true);
- }
+ set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
+ set_allow_modules(!info->is_native() && FLAG_harmony_modules);
+ set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native());
+ set_allow_lazy(false); // Must be explicitly enabled.
+ set_allow_generators(FLAG_harmony_generators);
}
@@ -617,7 +612,7 @@
ZoneScope* zone_scope) {
ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL);
- if (pre_data_ != NULL) pre_data_->Initialize();
+ if (pre_parse_data_ != NULL) pre_parse_data_->Initialize();
Handle<String> no_name = isolate()->factory()->empty_string();
@@ -638,15 +633,16 @@
scope->set_end_position(source->length());
// Compute the parsing mode.
- Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
- if (allow_natives_syntax_ || extension_ != NULL || scope->is_eval_scope()) {
+ Mode mode = (FLAG_lazy && allow_lazy()) ? PARSE_LAZILY : PARSE_EAGERLY;
+ if (allow_natives_syntax() ||
+ extension_ != NULL ||
+ scope->is_eval_scope()) {
mode = PARSE_EAGERLY;
}
ParsingModeScope parsing_mode(this, mode);
- bool is_generator = false;
// Enters 'scope'.
- FunctionState function_state(this, scope, is_generator, isolate());
+ FunctionState function_state(this, scope, isolate());
top_scope_->SetLanguageMode(info->language_mode());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
@@ -760,8 +756,7 @@
scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
zone());
}
- bool is_generator = false; // Top scope is not a generator.
- FunctionState function_state(this, scope, is_generator, isolate());
+ FunctionState function_state(this, scope, isolate());
ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
ASSERT(scope->language_mode() != EXTENDED_MODE ||
info()->is_extended_mode());
@@ -801,8 +796,8 @@
Handle<String> Parser::GetSymbol(bool* ok) {
int symbol_id = -1;
- if (pre_data() != NULL) {
- symbol_id = pre_data()->GetSymbolIdentifier();
+ if (pre_parse_data() != NULL) {
+ symbol_id = pre_parse_data()->GetSymbolIdentifier();
}
return LookupSymbol(symbol_id);
}
@@ -1092,7 +1087,7 @@
mode_ = PARSE_EAGERLY;
}
// TODO(ES6): Fix entering extended mode, once it is specified.
- top_scope_->SetLanguageMode(FLAG_harmony_scoping
+ top_scope_->SetLanguageMode(allow_harmony_scoping()
? EXTENDED_MODE : STRICT_MODE);
// "use strict" is the only directive for now.
directive_prologue = false;
@@ -1910,7 +1905,7 @@
// '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
- bool is_generator = FLAG_harmony_generators && Check(Token::MUL);
+ bool is_generator = allow_generators() && Check(Token::MUL);
bool is_strict_reserved = false;
Handle<String> name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
@@ -3105,8 +3100,11 @@
int position = scanner().peek_location().beg_pos;
Expect(Token::YIELD, CHECK_OK);
bool is_yield_star = Check(Token::MUL);
+ Expression* generator_object = factory()->NewVariableProxy(
+ current_function_state_->generator_object_variable());
Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
- return factory()->NewYield(expression, is_yield_star, position);
+ return factory()->NewYield(generator_object, expression, is_yield_star,
+ position);
}
@@ -3486,7 +3484,7 @@
if (peek() == Token::FUNCTION) {
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
- bool is_generator = FLAG_harmony_generators && Check(Token::MUL);
+ bool is_generator = allow_generators() && Check(Token::MUL);
Handle<String> name;
bool is_strict_reserved_name = false;
if (peek_any_identifier()) {
@@ -3702,7 +3700,7 @@
break;
case Token::MOD:
- if (allow_natives_syntax_ || extension_ != NULL) {
+ if (allow_natives_syntax() || extension_ != NULL) {
result = ParseV8Intrinsic(CHECK_OK);
break;
}
@@ -4391,9 +4389,25 @@
: FunctionLiteral::kNotGenerator;
AstProperties ast_properties;
// Parse function body.
- { FunctionState function_state(this, scope, is_generator, isolate());
+ { FunctionState function_state(this, scope, isolate());
top_scope_->SetScopeName(function_name);
+ if (is_generator) {
+ // For generators, allocating variables in contexts is currently a win
+ // because it minimizes the work needed to suspend and resume an
+ // activation.
+ top_scope_->ForceContextAllocation();
+
+ // Calling a generator returns a generator object. That object is stored
+ // in a temporary variable, a definition that is used by "yield"
+ // expressions. Presence of a variable for the generator object in the
+ // FunctionState indicates that this function is a generator.
+ Handle<String> tempname = isolate()->factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR(".generator_object"));
+ Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
+ function_state.set_generator_object_variable(temp);
+ }
+
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
@@ -4475,11 +4489,11 @@
if (is_lazily_compiled) {
int function_block_pos = scanner().location().beg_pos;
FunctionEntry entry;
- if (pre_data_ != NULL) {
- // If we have pre_data_, we use it to skip parsing the function body.
- // the preparser data contains the information we need to construct the
- // lazy function.
- entry = pre_data()->GetFunctionEntry(function_block_pos);
+ if (pre_parse_data_ != NULL) {
+ // If we have pre_parse_data_, we use it to skip parsing the function
+ // body. The preparser data contains the information we need to
+ // construct the lazy function.
+ entry = pre_parse_data()->GetFunctionEntry(function_block_pos);
if (entry.is_valid()) {
if (entry.end_pos() <= function_block_pos) {
// End position greater than end of stream is safe, and hard
@@ -4550,6 +4564,26 @@
RelocInfo::kNoPosition)),
zone());
}
+
+ // For generators, allocate and yield an iterator on function entry.
+ if (is_generator) {
+ ZoneList<Expression*>* arguments =
+ new(zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* allocation = factory()->NewCallRuntime(
+ isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject),
+ arguments);
+ VariableProxy* init_proxy = factory()->NewVariableProxy(
+ current_function_state_->generator_object_variable());
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
+ VariableProxy* get_proxy = factory()->NewVariableProxy(
+ current_function_state_->generator_object_variable());
+ Yield* yield = factory()->NewYield(
+ get_proxy, assignment, false, RelocInfo::kNoPosition);
+ body->Add(factory()->NewExpressionStatement(yield), zone());
+ }
+
ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
materialized_literal_count = function_state.materialized_literal_count();
@@ -4646,14 +4680,14 @@
if (reusable_preparser_ == NULL) {
intptr_t stack_limit = isolate()->stack_guard()->real_climit();
- bool do_allow_lazy = true;
reusable_preparser_ = new preparser::PreParser(&scanner_,
NULL,
- stack_limit,
- do_allow_lazy,
- allow_natives_syntax_,
- allow_modules_,
- FLAG_harmony_generators);
+ stack_limit);
+ reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
+ reusable_preparser_->set_allow_modules(allow_modules());
+ reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
+ reusable_preparser_->set_allow_lazy(true);
+ reusable_preparser_->set_allow_generators(allow_generators());
}
preparser::PreParser::PreParseResult result =
reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
@@ -5900,20 +5934,18 @@
// Create a Scanner for the preparser to use as input, and preparse the source.
-static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source,
- int flags,
- ParserRecorder* recorder) {
+ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) {
+ CompleteParserRecorder recorder;
Isolate* isolate = Isolate::Current();
HistogramTimerScope timer(isolate->counters()->pre_parse());
Scanner scanner(isolate->unicode_cache());
- scanner.SetHarmonyScoping(FLAG_harmony_scoping);
- scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
- preparser::PreParser::PreParseResult result =
- preparser::PreParser::PreParseProgram(&scanner,
- recorder,
- flags,
- stack_limit);
+ preparser::PreParser preparser(&scanner, &recorder, stack_limit);
+ preparser.set_allow_lazy(true);
+ preparser.set_allow_generators(FLAG_harmony_generators);
+ preparser.set_allow_harmony_scoping(FLAG_harmony_scoping);
+ scanner.Initialize(source);
+ preparser::PreParser::PreParseResult result = preparser.PreParseProgram();
if (result == preparser::PreParser::kPreParseStackOverflow) {
isolate->StackOverflow();
return NULL;
@@ -5921,26 +5953,11 @@
// Extract the accumulated data from the recorder as a single
// contiguous vector that we are responsible for disposing.
- Vector<unsigned> store = recorder->ExtractData();
+ Vector<unsigned> store = recorder.ExtractData();
return new ScriptDataImpl(store);
}
-ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source,
- v8::Extension* extension,
- int flags) {
- Handle<Script> no_script;
- if (FLAG_lazy && (extension == NULL)) {
- flags |= kAllowLazy;
- }
- if (FLAG_harmony_generators) {
- flags |= kAllowGenerators;
- }
- CompleteParserRecorder recorder;
- return DoPreParse(source, flags, &recorder);
-}
-
-
bool RegExpParser::ParseRegExp(FlatStringReader* input,
bool multiline,
RegExpCompileData* result,
@@ -5964,48 +5981,35 @@
}
-bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
- ASSERT(info->function() == NULL);
+bool Parser::Parse() {
+ ASSERT(info()->function() == NULL);
FunctionLiteral* result = NULL;
- ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE);
- if (!info->is_native() && FLAG_harmony_scoping) {
- // Harmony scoping is requested.
- parsing_flags |= EXTENDED_MODE;
- }
- if (!info->is_native() && FLAG_harmony_modules) {
- parsing_flags |= kAllowModules;
- }
- if (FLAG_allow_natives_syntax || info->is_native()) {
- // We require %identifier(..) syntax.
- parsing_flags |= kAllowNativesSyntax;
- }
- if (info->is_lazy()) {
- ASSERT(!info->is_eval());
- Parser parser(info, parsing_flags, NULL, NULL);
- if (info->shared_info()->is_function()) {
- result = parser.ParseLazy();
+ if (info()->is_lazy()) {
+ ASSERT(!info()->is_eval());
+ if (info()->shared_info()->is_function()) {
+ result = ParseLazy();
} else {
- result = parser.ParseProgram();
+ result = ParseProgram();
}
} else {
- ScriptDataImpl* pre_data = info->pre_parse_data();
- Parser parser(info, parsing_flags, info->extension(), pre_data);
- if (pre_data != NULL && pre_data->has_error()) {
- Scanner::Location loc = pre_data->MessageLocation();
- const char* message = pre_data->BuildMessage();
- Vector<const char*> args = pre_data->BuildArgs();
- parser.ReportMessageAt(loc, message, args);
+ ScriptDataImpl* pre_parse_data = info()->pre_parse_data();
+ set_pre_parse_data(pre_parse_data);
+ if (pre_parse_data != NULL && pre_parse_data->has_error()) {
+ Scanner::Location loc = pre_parse_data->MessageLocation();
+ const char* message = pre_parse_data->BuildMessage();
+ Vector<const char*> args = pre_parse_data->BuildArgs();
+ ReportMessageAt(loc, message, args);
DeleteArray(message);
for (int i = 0; i < args.length(); i++) {
DeleteArray(args[i]);
}
DeleteArray(args.start());
- ASSERT(info->isolate()->has_pending_exception());
+ ASSERT(info()->isolate()->has_pending_exception());
} else {
- result = parser.ParseProgram();
+ result = ParseProgram();
}
}
- info->SetFunction(result);
+ info()->SetFunction(result);
return (result != NULL);
}
diff --git a/src/parser.h b/src/parser.h
index fc4aba2..acf47bb 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -163,19 +163,17 @@
};
-class ParserApi {
+class PreParserApi {
public:
- // Parses the source code represented by the compilation info and sets its
- // function literal. Returns false (and deallocates any allocated AST
- // nodes) if parsing failed.
- static bool Parse(CompilationInfo* info, int flags);
-
- // Generic preparser generating full preparse data.
- static ScriptDataImpl* PreParse(Utf16CharacterStream* source,
- v8::Extension* extension,
- int flags);
+ // Pre-parse a character stream and return full preparse data.
+ //
+ // This interface is here instead of in preparser.h because it instantiates a
+ // preparser recorder object that is suited to the parser's purposes. Also,
+ // the preparser doesn't know about ScriptDataImpl.
+ static ScriptDataImpl* PreParse(Utf16CharacterStream* source);
};
+
// ----------------------------------------------------------------------------
// REGEXP PARSING
@@ -295,7 +293,7 @@
};
-class RegExpParser {
+class RegExpParser BASE_EMBEDDED {
public:
RegExpParser(FlatStringReader* in,
Handle<String>* error,
@@ -425,20 +423,36 @@
// Forward declaration.
class SingletonLogger;
-class Parser {
+class Parser BASE_EMBEDDED {
public:
- Parser(CompilationInfo* info,
- int parsing_flags, // Combination of ParsingFlags
- v8::Extension* extension,
- ScriptDataImpl* pre_data);
- virtual ~Parser() {
+ explicit Parser(CompilationInfo* info);
+ ~Parser() {
delete reusable_preparser_;
reusable_preparser_ = NULL;
}
+ bool allow_natives_syntax() const { return allow_natives_syntax_; }
+ bool allow_lazy() const { return allow_lazy_; }
+ bool allow_modules() { return scanner().HarmonyModules(); }
+ bool allow_harmony_scoping() { return scanner().HarmonyScoping(); }
+ bool allow_generators() const { return allow_generators_; }
+
+ void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
+ void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
+ void set_allow_modules(bool allow) { scanner().SetHarmonyModules(allow); }
+ void set_allow_harmony_scoping(bool allow) {
+ scanner().SetHarmonyScoping(allow);
+ }
+ void set_allow_generators(bool allow) { allow_generators_ = allow; }
+
+ // Parses the source code represented by the compilation info and sets its
+ // function literal. Returns false (and deallocates any allocated AST
+ // nodes) if parsing failed.
+ static bool Parse(CompilationInfo* info) { return Parser(info).Parse(); }
+ bool Parse();
+
// Returns NULL if parsing failed.
FunctionLiteral* ParseProgram();
- FunctionLiteral* ParseLazy();
void ReportMessageAt(Scanner::Location loc,
const char* message,
@@ -474,7 +488,6 @@
public:
FunctionState(Parser* parser,
Scope* scope,
- bool is_generator,
Isolate* isolate);
~FunctionState();
@@ -505,7 +518,17 @@
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
- bool is_generator() const { return is_generator_; }
+ void set_generator_object_variable(Variable *variable) {
+ ASSERT(variable != NULL);
+ ASSERT(!is_generator());
+ generator_object_variable_ = variable;
+ }
+ Variable* generator_object_variable() const {
+ return generator_object_variable_;
+ }
+ bool is_generator() const {
+ return generator_object_variable_ != NULL;
+ }
AstNodeFactory<AstConstructionVisitor>* factory() { return &factory_; }
@@ -521,14 +544,16 @@
// Properties count estimation.
int expected_property_count_;
- // Indicates that this function is a generator.
- bool is_generator_;
-
// Keeps track of assignments to properties of this. Used for
// optimizing constructors.
bool only_simple_this_property_assignments_;
Handle<FixedArray> this_property_assignments_;
+ // For generators, the variable that holds the generator object. This
+ // variable is used by yield expressions and return statements. NULL
+ // indicates that this function is not a generator.
+ Variable* generator_object_variable_;
+
Parser* parser_;
FunctionState* outer_function_state_;
Scope* outer_scope_;
@@ -552,6 +577,7 @@
Mode old_mode_;
};
+ FunctionLiteral* ParseLazy();
FunctionLiteral* ParseLazy(Utf16CharacterStream* source,
ZoneScope* zone_scope);
@@ -570,10 +596,15 @@
void ReportMessage(const char* message, Vector<const char*> args);
void ReportMessage(const char* message, Vector<Handle<String> > args);
+ void set_pre_parse_data(ScriptDataImpl *data) {
+ pre_parse_data_ = data;
+ symbol_cache_.Initialize(data ? data->symbol_count() : 0, zone());
+ }
+
bool inside_with() const { return top_scope_->inside_with(); }
Scanner& scanner() { return scanner_; }
Mode mode() const { return mode_; }
- ScriptDataImpl* pre_data() const { return pre_data_; }
+ ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
bool is_extended_mode() {
ASSERT(top_scope_ != NULL);
return top_scope_->is_extended_mode();
@@ -835,13 +866,13 @@
FunctionState* current_function_state_;
Target* target_stack_; // for break, continue statements
v8::Extension* extension_;
- ScriptDataImpl* pre_data_;
+ ScriptDataImpl* pre_parse_data_;
FuncNameInferrer* fni_;
Mode mode_;
bool allow_natives_syntax_;
bool allow_lazy_;
- bool allow_modules_;
+ bool allow_generators_;
bool stack_overflow_;
// If true, the next (and immediately following) function literal is
// preceded by a parenthesis.
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index 67c389e..6804af8 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -43,6 +43,7 @@
#include "platform-posix.h"
#include "platform.h"
+#include "simulator.h"
#include "v8threads.h"
#include "vm-state-inl.h"
#include "win32-headers.h"
@@ -193,6 +194,11 @@
}
+void OS::DumpBacktrace() {
+ // Currently unsupported.
+}
+
+
class PosixMemoryMappedFile : public OS::MemoryMappedFile {
public:
PosixMemoryMappedFile(FILE* file, void* memory, int size)
@@ -318,38 +324,127 @@
// This causes VirtualMemory::Commit to not always commit the memory region
// specified.
-bool VirtualMemory::IsReserved() {
- return address_ != NULL;
+static void* GetRandomAddr() {
+ Isolate* isolate = Isolate::UncheckedCurrent();
+ // Note that the current isolate isn't set up in a call path via
+ // CpuFeatures::Probe. We don't care about randomization in this case because
+ // the code page is immediately freed.
+ if (isolate != NULL) {
+ // The address range used to randomize RWX allocations in OS::Allocate
+ // Try not to map pages into the default range that windows loads DLLs
+ // Use a multiple of 64k to prevent committing unused memory.
+ // Note: This does not guarantee RWX regions will be within the
+ // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
+#ifdef V8_HOST_ARCH_64_BIT
+ static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
+ static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
+#else
+ static const intptr_t kAllocationRandomAddressMin = 0x04000000;
+ static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
+#endif
+ uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits)
+ | kAllocationRandomAddressMin;
+ address &= kAllocationRandomAddressMax;
+ return reinterpret_cast<void *>(address);
+ }
+ return NULL;
}
-VirtualMemory::VirtualMemory(size_t size) {
- address_ = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
- size_ = size;
+static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
+ LPVOID base = NULL;
+
+ if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
+ // For exectutable pages try and randomize the allocation address
+ for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
+ base = VirtualAlloc(GetRandomAddr(), size, action, protection);
+ }
+ }
+
+ // After three attempts give up and let the OS find an address to use.
+ if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
+
+ return base;
+}
+
+
+VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
+
+
+VirtualMemory::VirtualMemory(size_t size)
+ : address_(ReserveRegion(size)), size_(size) { }
+
+
+VirtualMemory::VirtualMemory(size_t size, size_t alignment)
+ : address_(NULL), size_(0) {
+ ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
+ size_t request_size = RoundUp(size + alignment,
+ static_cast<intptr_t>(OS::AllocateAlignment()));
+ void* address = ReserveRegion(request_size);
+ if (address == NULL) return;
+ Address base = RoundUp(static_cast<Address>(address), alignment);
+ // Try reducing the size by freeing and then reallocating a specific area.
+ bool result = ReleaseRegion(address, request_size);
+ USE(result);
+ ASSERT(result);
+ address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
+ if (address != NULL) {
+ request_size = size;
+ ASSERT(base == static_cast<Address>(address));
+ } else {
+ // Resizing failed, just go with a bigger area.
+ address = ReserveRegion(request_size);
+ if (address == NULL) return;
+ }
+ address_ = address;
+ size_ = request_size;
}
VirtualMemory::~VirtualMemory() {
if (IsReserved()) {
- if (0 == VirtualFree(address(), 0, MEM_RELEASE)) address_ = NULL;
+ bool result = ReleaseRegion(address_, size_);
+ ASSERT(result);
+ USE(result);
}
}
-bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
- int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
- if (NULL == VirtualAlloc(address, size, MEM_COMMIT, prot)) {
- return false;
- }
+bool VirtualMemory::IsReserved() {
+ return address_ != NULL;
+}
- UpdateAllocatedSpaceLimits(address, static_cast<int>(size));
- return true;
+
+void VirtualMemory::Reset() {
+ address_ = NULL;
+ size_ = 0;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
+ return CommitRegion(address, size, is_executable);
}
bool VirtualMemory::Uncommit(void* address, size_t size) {
ASSERT(IsReserved());
- return VirtualFree(address, size, MEM_DECOMMIT) != false;
+ return UncommitRegion(address, size);
+}
+
+
+void* VirtualMemory::ReserveRegion(size_t size) {
+ return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
+}
+
+
+bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
+ int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+ if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
+ return false;
+ }
+
+ UpdateAllocatedSpaceLimits(base, static_cast<int>(size));
+ return true;
}
@@ -364,6 +459,16 @@
}
+bool VirtualMemory::UncommitRegion(void* base, size_t size) {
+ return VirtualFree(base, size, MEM_DECOMMIT) != 0;
+}
+
+
+bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
+ return VirtualFree(base, 0, MEM_RELEASE) != 0;
+}
+
+
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
@@ -377,11 +482,10 @@
};
-
-
Thread::Thread(const Options& options)
: data_(new PlatformData()),
- stack_size_(options.stack_size()) {
+ stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
set_name(options.name());
}
@@ -398,7 +502,7 @@
// one) so we initialize it here too.
thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
+ thread->NotifyStartedAndRun();
return NULL;
}
@@ -591,143 +695,6 @@
}
-// ----------------------------------------------------------------------------
-// Cygwin profiler support.
-//
-// On Cygwin we use the same sampler implementation as on win32.
-
-class Sampler::PlatformData : public Malloced {
- public:
- // Get a handle to the calling thread. This is the thread that we are
- // going to profile. We need to make a copy of the handle because we are
- // going to use it in the sampler thread. Using GetThreadHandle() will
- // not work in this case. We're using OpenThread because DuplicateHandle
- // for some reason doesn't work in Chrome's sandbox.
- PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
- THREAD_SUSPEND_RESUME |
- THREAD_QUERY_INFORMATION,
- false,
- GetCurrentThreadId())) {}
-
- ~PlatformData() {
- if (profiled_thread_ != NULL) {
- CloseHandle(profiled_thread_);
- profiled_thread_ = NULL;
- }
- }
-
- HANDLE profiled_thread() { return profiled_thread_; }
-
- private:
- HANDLE profiled_thread_;
-};
-
-
-class SamplerThread : public Thread {
- public:
- static const int kSamplerThreadStackSize = 64 * KB;
-
- explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- instance_ = new SamplerThread(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- OS::Sleep(interval_);
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
- if (!sampler->isolate()->IsInitialized()) return;
- if (!sampler->IsProfiling()) return;
- SamplerThread* sampler_thread =
- reinterpret_cast<SamplerThread*>(raw_sampler_thread);
- sampler_thread->SampleContext(sampler);
- }
-
- void SampleContext(Sampler* sampler) {
- HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
- if (profiled_thread == NULL) return;
-
- // Context used for sampling the register state of the profiled thread.
- CONTEXT context;
- memset(&context, 0, sizeof(context));
-
- Isolate* isolate = sampler->isolate();
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
- if (SuspendThread(profiled_thread) == kSuspendFailed) return;
- sample->state = isolate->current_vm_state();
-
- context.ContextFlags = CONTEXT_FULL;
- if (GetThreadContext(profiled_thread, &context) != 0) {
-#if V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(context.Rip);
- sample->sp = reinterpret_cast<Address>(context.Rsp);
- sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
- sample->pc = reinterpret_cast<Address>(context.Eip);
- sample->sp = reinterpret_cast<Address>(context.Esp);
- sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
- sampler->SampleStack(sample);
- sampler->Tick(sample);
- }
- ResumeThread(profiled_thread);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SamplerThread* instance_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -737,44 +704,12 @@
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SamplerThread::SetUp();
}
void OS::TearDown() {
- SamplerThread::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SamplerThread::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 14f7171..735f078 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -357,12 +357,12 @@
static const int kMmapFd = -1;
static const int kMmapFdOffset = 0;
+
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
-VirtualMemory::VirtualMemory(size_t size) {
- address_ = ReserveRegion(size);
- size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+ : address_(ReserveRegion(size)), size_(size) { }
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -500,7 +500,8 @@
Thread::Thread(const Options& options)
: data_(new PlatformData),
- stack_size_(options.stack_size()) {
+ stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
set_name(options.name());
}
@@ -517,7 +518,7 @@
// one) so we initialize it here too.
thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
+ thread->NotifyStartedAndRun();
return NULL;
}
@@ -681,174 +682,6 @@
}
-static pthread_t GetThreadID() {
- pthread_t thread_id = pthread_self();
- return thread_id;
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData() : vm_tid_(GetThreadID()) {}
-
- pthread_t vm_tid() const { return vm_tid_; }
-
- private:
- pthread_t vm_tid_;
-};
-
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- USE(info);
- if (signal != SIGPROF) return;
- Isolate* isolate = Isolate::UncheckedCurrent();
- if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
- // We require a fully initialized and entered isolate.
- return;
- }
- if (v8::Locker::IsActive() &&
- !isolate->thread_manager()->IsLockedByCurrentThread()) {
- return;
- }
-
- Sampler* sampler = isolate->logger()->sampler();
- if (sampler == NULL || !sampler->IsActive()) return;
-
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- // Extracting the sample from the context is extremely machine dependent.
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
- mcontext_t& mcontext = ucontext->uc_mcontext;
- sample->state = isolate->current_vm_state();
-#if V8_HOST_ARCH_IA32
- sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
- sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
- sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
-#elif V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
- sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
- sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
-#elif V8_HOST_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
- sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
- sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
-#endif
- sampler->SampleStack(sample);
- sampler->Tick(sample);
-}
-
-
-class SignalSender : public Thread {
- public:
- static const int kSignalSenderStackSize = 64 * KB;
-
- explicit SignalSender(int interval)
- : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- // Install a signal handler.
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- signal_handler_installed_ =
- (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
-
- // Start a thread that sends SIGPROF signal to VM threads.
- instance_ = new SignalSender(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
-
- // Restore the old signal handler.
- if (signal_handler_installed_) {
- sigaction(SIGPROF, &old_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
- if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
- }
-
- void SendProfilingSignal(pthread_t tid) {
- if (!signal_handler_installed_) return;
- pthread_kill(tid, SIGPROF);
- }
-
- void Sleep() {
- // Convert ms to us and subtract 100 us to compensate delays
- // occuring during signal delivery.
- useconds_t interval = interval_ * 1000 - 100;
- int result = usleep(interval);
-#ifdef DEBUG
- if (result != 0 && errno != EINTR) {
- fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
- interval,
- errno);
- ASSERT(result == 0 || errno == EINTR);
- }
-#endif
- USE(result);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SignalSender* instance_;
- static bool signal_handler_installed_;
- static struct sigaction old_signal_handler_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -858,44 +691,12 @@
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SignalSender::SetUp();
}
void OS::TearDown() {
- SignalSender::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 1f9cde1..38f7c67 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -38,7 +38,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#if defined(__GLIBC__)
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
#include <execinfo.h>
#include <cxxabi.h>
#endif
@@ -51,9 +51,6 @@
#include <sys/stat.h> // open
#include <fcntl.h> // open
#include <unistd.h> // sysconf
-#if defined(__GLIBC__) && !defined(__UCLIBC__)
-#include <execinfo.h> // backtrace, backtrace_symbols
-#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
#include <strings.h> // index
#include <errno.h>
#include <stdarg.h>
@@ -146,9 +143,6 @@
// facility is universally available on the ARM architectures,
// so it's up to individual OSes to provide such.
switch (feature) {
- case VFP2:
- search_string = "vfp";
- break;
case VFP3:
search_string = "vfpv3";
break;
@@ -272,8 +266,10 @@
FILE* f = NULL;
const char* what = search_string;
- if (NULL == (f = fopen(file_name, "r")))
+ if (NULL == (f = fopen(file_name, "r"))) {
+ OS::PrintError("Failed to open /proc/cpuinfo\n");
return false;
+ }
int k;
while (EOF != (k = fgetc(f))) {
@@ -428,6 +424,8 @@
# endif
#elif defined(__mips__)
asm("break");
+#elif defined(__native_client__)
+ asm("hlt");
#else
asm("int $3");
#endif
@@ -435,7 +433,7 @@
void OS::DumpBacktrace() {
-#if defined(__GLIBC__)
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
void* trace[100];
int size = backtrace(trace, ARRAY_SIZE(trace));
char** symbols = backtrace_symbols(trace, size);
@@ -644,12 +642,12 @@
static const int kMmapFd = -1;
static const int kMmapFdOffset = 0;
+
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
-VirtualMemory::VirtualMemory(size_t size) {
- address_ = ReserveRegion(size);
- size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+ : address_(ReserveRegion(size)), size_(size) { }
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -787,7 +785,8 @@
Thread::Thread(const Options& options)
: data_(new PlatformData()),
- stack_size_(options.stack_size()) {
+ stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
set_name(options.name());
}
@@ -809,7 +808,7 @@
#endif
thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
+ thread->NotifyStartedAndRun();
return NULL;
}
@@ -822,12 +821,16 @@
void Thread::Start() {
pthread_attr_t* attr_ptr = NULL;
+#if defined(__native_client__)
+ // use default stack size.
+#else
pthread_attr_t attr;
if (stack_size_ > 0) {
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
attr_ptr = &attr;
}
+#endif
int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
CHECK_EQ(0, result);
ASSERT(data_->thread_ != kNoThread);
@@ -988,349 +991,17 @@
}
-#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
-
-// Not all versions of Android's C library provide ucontext_t.
-// Detect this and provide custom but compatible definitions. Note that these
-// follow the GLibc naming convention to access register values from
-// mcontext_t.
-//
-// See http://code.google.com/p/android/issues/detail?id=34784
-
-#if defined(__arm__)
-
-typedef struct sigcontext mcontext_t;
-
-typedef struct ucontext {
- uint32_t uc_flags;
- struct ucontext* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- // Other fields are not used by V8, don't define them here.
-} ucontext_t;
-
-#elif defined(__mips__)
-// MIPS version of sigcontext, for Android bionic.
-typedef struct {
- uint32_t regmask;
- uint32_t status;
- uint64_t pc;
- uint64_t gregs[32];
- uint64_t fpregs[32];
- uint32_t acx;
- uint32_t fpc_csr;
- uint32_t fpc_eir;
- uint32_t used_math;
- uint32_t dsp;
- uint64_t mdhi;
- uint64_t mdlo;
- uint32_t hi1;
- uint32_t lo1;
- uint32_t hi2;
- uint32_t lo2;
- uint32_t hi3;
- uint32_t lo3;
-} mcontext_t;
-
-typedef struct ucontext {
- uint32_t uc_flags;
- struct ucontext* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- // Other fields are not used by V8, don't define them here.
-} ucontext_t;
-
-#elif defined(__i386__)
-// x86 version for Android.
-typedef struct {
- uint32_t gregs[19];
- void* fpregs;
- uint32_t oldmask;
- uint32_t cr2;
-} mcontext_t;
-
-typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
-typedef struct ucontext {
- uint32_t uc_flags;
- struct ucontext* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- // Other fields are not used by V8, don't define them here.
-} ucontext_t;
-enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
-#endif
-
-#endif // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
-
-static int GetThreadID() {
-#if defined(__ANDROID__)
- // Android's C library provides gettid(2).
- return gettid();
-#else
- // Glibc doesn't provide a wrapper for gettid(2).
- return syscall(SYS_gettid);
-#endif
-}
-
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- USE(info);
- if (signal != SIGPROF) return;
- Isolate* isolate = Isolate::UncheckedCurrent();
- if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
- // We require a fully initialized and entered isolate.
- return;
- }
- if (v8::Locker::IsActive() &&
- !isolate->thread_manager()->IsLockedByCurrentThread()) {
- return;
- }
-
- Sampler* sampler = isolate->logger()->sampler();
- if (sampler == NULL || !sampler->IsActive()) return;
-
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- // Extracting the sample from the context is extremely machine dependent.
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
- mcontext_t& mcontext = ucontext->uc_mcontext;
- sample->state = isolate->current_vm_state();
-#if V8_HOST_ARCH_IA32
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
-#elif V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
-#elif V8_HOST_ARCH_ARM
-#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
- (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
- // Old GLibc ARM versions used a gregs[] array to access the register
- // values from mcontext_t.
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
-#else
- sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
- sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
- sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
-#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
- // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
-#elif V8_HOST_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(mcontext.pc);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
-#endif // V8_HOST_ARCH_*
- sampler->SampleStack(sample);
- sampler->Tick(sample);
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData() : vm_tid_(GetThreadID()) {}
-
- int vm_tid() const { return vm_tid_; }
-
- private:
- const int vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
- static const int kSignalSenderStackSize = 64 * KB;
-
- explicit SignalSender(int interval)
- : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- vm_tgid_(getpid()),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void InstallSignalHandler() {
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- signal_handler_installed_ =
- (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
- }
-
- static void RestoreSignalHandler() {
- if (signal_handler_installed_) {
- sigaction(SIGPROF, &old_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
- }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- // Start a thread that will send SIGPROF signal to VM threads,
- // when CPU profiling will be enabled.
- instance_ = new SignalSender(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- RestoreSignalHandler();
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- if (!signal_handler_installed_) InstallSignalHandler();
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (signal_handler_installed_) RestoreSignalHandler();
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
- if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
- }
-
- void SendProfilingSignal(int tid) {
- if (!signal_handler_installed_) return;
- // Glibc doesn't provide a wrapper for tgkill(2).
-#if defined(ANDROID)
- syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
-#else
- int result = syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
- USE(result);
- ASSERT(result == 0);
-#endif
- }
-
- void Sleep() {
- // Convert ms to us and subtract 100 us to compensate delays
- // occuring during signal delivery.
- useconds_t interval = interval_ * 1000 - 100;
-#if defined(ANDROID)
- usleep(interval);
-#else
- int result = usleep(interval);
-#ifdef DEBUG
- if (result != 0 && errno != EINTR) {
- fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
- interval,
- errno);
- ASSERT(result == 0 || errno == EINTR);
- }
-#endif // DEBUG
- USE(result);
-#endif // ANDROID
- }
-
- const int vm_tgid_;
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SignalSender* instance_;
- static bool signal_handler_installed_;
- static struct sigaction old_signal_handler_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
void OS::SetUp() {
// Seed the random number generator. We preserve microsecond resolution.
uint64_t seed = Ticks() ^ (getpid() << 16);
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
-
-#ifdef __arm__
- // When running on ARM hardware check that the EABI used by V8 and
- // by the C code is the same.
- bool hard_float = OS::ArmUsingHardFloat();
- if (hard_float) {
-#if !USE_EABI_HARDFLOAT
- PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
- "-DUSE_EABI_HARDFLOAT\n");
- exit(1);
-#endif
- } else {
-#if USE_EABI_HARDFLOAT
- PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
- "-DUSE_EABI_HARDFLOAT\n");
- exit(1);
-#endif
- }
-#endif
- SignalSender::SetUp();
}
void OS::TearDown() {
- SignalSender::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 30e2b89..9bb4dbd 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -60,6 +60,7 @@
#include "platform-posix.h"
#include "platform.h"
+#include "simulator.h"
#include "vm-state-inl.h"
// Manually define these here as weak imports, rather than including execinfo.h.
@@ -407,12 +408,33 @@
}
+bool VirtualMemory::IsReserved() {
+ return address_ != NULL;
+}
+
+
void VirtualMemory::Reset() {
address_ = NULL;
size_ = 0;
}
+bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
+ return CommitRegion(address, size, is_executable);
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+ return UncommitRegion(address, size);
+}
+
+
+bool VirtualMemory::Guard(void* address) {
+ OS::Guard(address, OS::CommitPageSize());
+ return true;
+}
+
+
void* VirtualMemory::ReserveRegion(size_t size) {
void* result = mmap(OS::GetRandomMmapAddr(),
size,
@@ -427,22 +449,6 @@
}
-bool VirtualMemory::IsReserved() {
- return address_ != NULL;
-}
-
-
-bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
- return CommitRegion(address, size, is_executable);
-}
-
-
-bool VirtualMemory::Guard(void* address) {
- OS::Guard(address, OS::CommitPageSize());
- return true;
-}
-
-
bool VirtualMemory::CommitRegion(void* address,
size_t size,
bool is_executable) {
@@ -461,11 +467,6 @@
}
-bool VirtualMemory::Uncommit(void* address, size_t size) {
- return UncommitRegion(address, size);
-}
-
-
bool VirtualMemory::UncommitRegion(void* address, size_t size) {
return mmap(address,
size,
@@ -495,7 +496,8 @@
Thread::Thread(const Options& options)
: data_(new PlatformData),
- stack_size_(options.stack_size()) {
+ stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
set_name(options.name());
}
@@ -530,7 +532,7 @@
thread->data()->thread_ = pthread_self();
SetThreadName(thread->name());
ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
+ thread->NotifyStartedAndRun();
return NULL;
}
@@ -741,186 +743,17 @@
}
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData() : profiled_thread_(mach_thread_self()) {}
-
- ~PlatformData() {
- // Deallocate Mach port for thread.
- mach_port_deallocate(mach_task_self(), profiled_thread_);
- }
-
- thread_act_t profiled_thread() { return profiled_thread_; }
-
- private:
- // Note: for profiled_thread_ Mach primitives are used instead of PThread's
- // because the latter doesn't provide thread manipulation primitives required.
- // For details, consult "Mac OS X Internals" book, Section 7.3.
- thread_act_t profiled_thread_;
-};
-
-
-class SamplerThread : public Thread {
- public:
- static const int kSamplerThreadStackSize = 64 * KB;
-
- explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- instance_ = new SamplerThread(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- OS::Sleep(interval_);
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
- if (!sampler->isolate()->IsInitialized()) return;
- if (!sampler->IsProfiling()) return;
- SamplerThread* sampler_thread =
- reinterpret_cast<SamplerThread*>(raw_sampler_thread);
- sampler_thread->SampleContext(sampler);
- }
-
- void SampleContext(Sampler* sampler) {
- thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
- Isolate* isolate = sampler->isolate();
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
-
-#if V8_HOST_ARCH_X64
- thread_state_flavor_t flavor = x86_THREAD_STATE64;
- x86_thread_state64_t state;
- mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
-#if __DARWIN_UNIX03
-#define REGISTER_FIELD(name) __r ## name
-#else
-#define REGISTER_FIELD(name) r ## name
-#endif // __DARWIN_UNIX03
-#elif V8_HOST_ARCH_IA32
- thread_state_flavor_t flavor = i386_THREAD_STATE;
- i386_thread_state_t state;
- mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
-#if __DARWIN_UNIX03
-#define REGISTER_FIELD(name) __e ## name
-#else
-#define REGISTER_FIELD(name) e ## name
-#endif // __DARWIN_UNIX03
-#else
-#error Unsupported Mac OS X host architecture.
-#endif // V8_HOST_ARCH
-
- if (thread_get_state(profiled_thread,
- flavor,
- reinterpret_cast<natural_t*>(&state),
- &count) == KERN_SUCCESS) {
- sample->state = isolate->current_vm_state();
- sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
- sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
- sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
- sampler->SampleStack(sample);
- sampler->Tick(sample);
- }
- thread_resume(profiled_thread);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SamplerThread* instance_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-#undef REGISTER_FIELD
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
void OS::SetUp() {
// Seed the random number generator. We preserve microsecond resolution.
uint64_t seed = Ticks() ^ (getpid() << 16);
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SamplerThread::SetUp();
}
void OS::TearDown() {
- SamplerThread::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SamplerThread::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index 0fef063..1b481f4 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -317,6 +317,16 @@
}
+VirtualMemory::VirtualMemory() {
+ UNIMPLEMENTED();
+}
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+ UNIMPLEMENTED();
+}
+
+
VirtualMemory::VirtualMemory(size_t size, void* address_hint) {
UNIMPLEMENTED();
}
@@ -333,6 +343,11 @@
}
+void VirtualMemory::Reset() {
+ UNIMPLEMENTED();
+}
+
+
bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
UNIMPLEMENTED();
return false;
@@ -351,6 +366,30 @@
}
+void* VirtualMemory::ReserveRegion(size_t size) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool VirtualMemory::UncommitRegion(void* base, size_t size) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
@@ -369,7 +408,8 @@
Thread::Thread(const Options& options)
: data_(new PlatformData()),
- stack_size_(options.stack_size) {
+ stack_size_(options.stack_size),
+ start_semaphore_(NULL) {
set_name(options.name);
UNIMPLEMENTED();
}
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index e48d4cb..e1aff17 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -385,12 +385,12 @@
static const int kMmapFd = -1;
static const int kMmapFdOffset = 0;
+
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
-VirtualMemory::VirtualMemory(size_t size) {
- address_ = ReserveRegion(size);
- size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+ : address_(ReserveRegion(size)), size_(size) { }
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -529,7 +529,8 @@
Thread::Thread(const Options& options)
: data_(new PlatformData()),
- stack_size_(options.stack_size()) {
+ stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
set_name(options.name());
}
@@ -551,7 +552,7 @@
#endif
thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
+ thread->NotifyStartedAndRun();
return NULL;
}
@@ -727,232 +728,17 @@
}
-static pthread_t GetThreadID() {
- return pthread_self();
-}
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- USE(info);
- if (signal != SIGPROF) return;
- Isolate* isolate = Isolate::UncheckedCurrent();
- if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
- // We require a fully initialized and entered isolate.
- return;
- }
- if (v8::Locker::IsActive() &&
- !isolate->thread_manager()->IsLockedByCurrentThread()) {
- return;
- }
-
- Sampler* sampler = isolate->logger()->sampler();
- if (sampler == NULL || !sampler->IsActive()) return;
-
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- // Extracting the sample from the context is extremely machine dependent.
- sample->state = isolate->current_vm_state();
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-#ifdef __NetBSD__
- mcontext_t& mcontext = ucontext->uc_mcontext;
-#if V8_HOST_ARCH_IA32
- sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
- sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
- sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
-#elif V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
- sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
- sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
-#endif // V8_HOST_ARCH
-#else // OpenBSD
-#if V8_HOST_ARCH_IA32
- sample->pc = reinterpret_cast<Address>(ucontext->sc_eip);
- sample->sp = reinterpret_cast<Address>(ucontext->sc_esp);
- sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp);
-#elif V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
- sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
- sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
-#endif // V8_HOST_ARCH
-#endif // __NetBSD__
- sampler->SampleStack(sample);
- sampler->Tick(sample);
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData() : vm_tid_(GetThreadID()) {}
-
- pthread_t vm_tid() const { return vm_tid_; }
-
- private:
- pthread_t vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
- static const int kSignalSenderStackSize = 64 * KB;
-
- explicit SignalSender(int interval)
- : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- vm_tgid_(getpid()),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void InstallSignalHandler() {
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- signal_handler_installed_ =
- (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
- }
-
- static void RestoreSignalHandler() {
- if (signal_handler_installed_) {
- sigaction(SIGPROF, &old_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
- }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- // Start a thread that will send SIGPROF signal to VM threads,
- // when CPU profiling will be enabled.
- instance_ = new SignalSender(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- RestoreSignalHandler();
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- if (!signal_handler_installed_) InstallSignalHandler();
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (signal_handler_installed_) RestoreSignalHandler();
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
- if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
- }
-
- void SendProfilingSignal(pthread_t tid) {
- if (!signal_handler_installed_) return;
- pthread_kill(tid, SIGPROF);
- }
-
- void Sleep() {
- // Convert ms to us and subtract 100 us to compensate delays
- // occuring during signal delivery.
- useconds_t interval = interval_ * 1000 - 100;
- int result = usleep(interval);
-#ifdef DEBUG
- if (result != 0 && errno != EINTR) {
- fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
- interval,
- errno);
- ASSERT(result == 0 || errno == EINTR);
- }
-#endif
- USE(result);
- }
-
- const int vm_tgid_;
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SignalSender* instance_;
- static bool signal_handler_installed_;
- static struct sigaction old_signal_handler_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
void OS::SetUp() {
// Seed the random number generator. We preserve microsecond resolution.
uint64_t seed = Ticks() ^ (getpid() << 16);
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SignalSender::SetUp();
}
void OS::TearDown() {
- SignalSender::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 0016d59..48898ed 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -94,6 +94,12 @@
void* OS::GetRandomMmapAddr() {
+#if defined(__native_client__)
+ // TODO(bradchen): restore randomization once Native Client gets
+ // smarter about using mmap address hints.
+ // See http://code.google.com/p/nativeclient/issues/3341
+ return NULL;
+#endif
Isolate* isolate = Isolate::UncheckedCurrent();
// Note that the current isolate isn't set up in a call path via
// CpuFeatures::Probe. We don't care about randomization in this case because
@@ -316,25 +322,32 @@
#if defined(V8_TARGET_ARCH_IA32)
-static OS::MemCopyFunction memcopy_function = NULL;
-// Defined in codegen-ia32.cc.
-OS::MemCopyFunction CreateMemCopyFunction();
+static void MemMoveWrapper(void* dest, const void* src, size_t size) {
+ memmove(dest, src, size);
+}
-// Copy memory area to disjoint memory area.
-void OS::MemCopy(void* dest, const void* src, size_t size) {
+// Initialize to library version so we can call this at any time during startup.
+static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
+
+// Defined in codegen-ia32.cc.
+OS::MemMoveFunction CreateMemMoveFunction();
+
+// Copy memory area. No restrictions.
+void OS::MemMove(void* dest, const void* src, size_t size) {
// Note: here we rely on dependent reads being ordered. This is true
// on all architectures we currently support.
- (*memcopy_function)(dest, src, size);
-#ifdef DEBUG
- CHECK_EQ(0, memcmp(dest, src, size));
-#endif
+ (*memmove_function)(dest, src, size);
}
+
#endif // V8_TARGET_ARCH_IA32
void POSIXPostSetUp() {
#if defined(V8_TARGET_ARCH_IA32)
- memcopy_function = CreateMemCopyFunction();
+ OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
+ if (generated_memmove != NULL) {
+ memmove_function = generated_memmove;
+ }
#endif
init_fast_sin_function();
init_fast_cos_function();
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 0e616d1..aeacab9 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -327,10 +327,9 @@
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
-VirtualMemory::VirtualMemory(size_t size) {
- address_ = ReserveRegion(size);
- size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+ : address_(ReserveRegion(size)), size_(size) { }
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -470,7 +469,8 @@
Thread::Thread(const Options& options)
: data_(new PlatformData()),
- stack_size_(options.stack_size()) {
+ stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
set_name(options.name());
}
@@ -487,7 +487,7 @@
// one) so we initialize it here too.
thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
+ thread->NotifyStartedAndRun();
return NULL;
}
@@ -661,169 +661,6 @@
}
-static pthread_t GetThreadID() {
- return pthread_self();
-}
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- USE(info);
- if (signal != SIGPROF) return;
- Isolate* isolate = Isolate::UncheckedCurrent();
- if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
- // We require a fully initialized and entered isolate.
- return;
- }
- if (v8::Locker::IsActive() &&
- !isolate->thread_manager()->IsLockedByCurrentThread()) {
- return;
- }
-
- Sampler* sampler = isolate->logger()->sampler();
- if (sampler == NULL || !sampler->IsActive()) return;
-
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- // Extracting the sample from the context is extremely machine dependent.
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
- mcontext_t& mcontext = ucontext->uc_mcontext;
- sample->state = isolate->current_vm_state();
-
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
-
- sampler->SampleStack(sample);
- sampler->Tick(sample);
-}
-
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData() : vm_tid_(GetThreadID()) {}
-
- pthread_t vm_tid() const { return vm_tid_; }
-
- private:
- pthread_t vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
- static const int kSignalSenderStackSize = 64 * KB;
-
- explicit SignalSender(int interval)
- : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void InstallSignalHandler() {
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- signal_handler_installed_ =
- (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
- }
-
- static void RestoreSignalHandler() {
- if (signal_handler_installed_) {
- sigaction(SIGPROF, &old_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
- }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- // Start a thread that will send SIGPROF signal to VM threads,
- // when CPU profiling will be enabled.
- instance_ = new SignalSender(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- RestoreSignalHandler();
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- if (!signal_handler_installed_) InstallSignalHandler();
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (signal_handler_installed_) RestoreSignalHandler();
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
- if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
- }
-
- void SendProfilingSignal(pthread_t tid) {
- if (!signal_handler_installed_) return;
- pthread_kill(tid, SIGPROF);
- }
-
- void Sleep() {
- // Convert ms to us and subtract 100 us to compensate delays
- // occuring during signal delivery.
- useconds_t interval = interval_ * 1000 - 100;
- int result = usleep(interval);
-#ifdef DEBUG
- if (result != 0 && errno != EINTR) {
- fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
- interval,
- errno);
- ASSERT(result == 0 || errno == EINTR);
- }
-#endif
- USE(result);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SignalSender* instance_;
- static bool signal_handler_installed_;
- static struct sigaction old_signal_handler_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -833,43 +670,12 @@
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SignalSender::SetUp();
}
void OS::TearDown() {
- SignalSender::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
- SetActive(false);
-}
-
} } // namespace v8::internal
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index c1bae93..272678f 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -45,6 +45,7 @@
#include "codegen.h"
#include "platform.h"
+#include "simulator.h"
#include "vm-state-inl.h"
#ifdef _MSC_VER
@@ -147,19 +148,23 @@
static Mutex* limit_mutex = NULL;
#if defined(V8_TARGET_ARCH_IA32)
-static OS::MemCopyFunction memcopy_function = NULL;
+static void MemMoveWrapper(void* dest, const void* src, size_t size) {
+ memmove(dest, src, size);
+}
+
+// Initialize to library version so we can call this at any time during startup.
+static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
+
// Defined in codegen-ia32.cc.
-OS::MemCopyFunction CreateMemCopyFunction();
+OS::MemMoveFunction CreateMemMoveFunction();
// Copy memory area to disjoint memory area.
-void OS::MemCopy(void* dest, const void* src, size_t size) {
+void OS::MemMove(void* dest, const void* src, size_t size) {
// Note: here we rely on dependent reads being ordered. This is true
// on all architectures we currently support.
- (*memcopy_function)(dest, src, size);
-#ifdef DEBUG
- CHECK_EQ(0, memcmp(dest, src, size));
-#endif
+ (*memmove_function)(dest, src, size);
}
+
#endif // V8_TARGET_ARCH_IA32
#ifdef _WIN64
@@ -575,7 +580,10 @@
// CPU.
MathSetup();
#if defined(V8_TARGET_ARCH_IA32)
- memcopy_function = CreateMemCopyFunction();
+ OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
+ if (generated_memmove != NULL) {
+ memmove_function = generated_memmove;
+ }
#endif
}
@@ -1061,7 +1069,7 @@
if (file_mapping == NULL) return NULL;
// Map a view of the file into memory
void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
- if (memory) memmove(memory, initial, size);
+ if (memory) OS::MemMove(memory, initial, size);
return new Win32MemoryMappedFile(file, file_mapping, memory, size);
}
@@ -1517,7 +1525,7 @@
VirtualMemory::~VirtualMemory() {
if (IsReserved()) {
- bool result = ReleaseRegion(address_, size_);
+ bool result = ReleaseRegion(address(), size());
ASSERT(result);
USE(result);
}
@@ -1536,11 +1544,7 @@
bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
- if (CommitRegion(address, size, is_executable)) {
- UpdateAllocatedSpaceLimits(address, static_cast<int>(size));
- return true;
- }
- return false;
+ return CommitRegion(address, size, is_executable);
}
@@ -1550,6 +1554,17 @@
}
+bool VirtualMemory::Guard(void* address) {
+ if (NULL == VirtualAlloc(address,
+ OS::CommitPageSize(),
+ MEM_COMMIT,
+ PAGE_READONLY | PAGE_GUARD)) {
+ return false;
+ }
+ return true;
+}
+
+
void* VirtualMemory::ReserveRegion(size_t size) {
return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
}
@@ -1566,17 +1581,6 @@
}
-bool VirtualMemory::Guard(void* address) {
- if (NULL == VirtualAlloc(address,
- OS::CommitPageSize(),
- MEM_COMMIT,
- PAGE_READONLY | PAGE_GUARD)) {
- return false;
- }
- return true;
-}
-
-
bool VirtualMemory::UncommitRegion(void* base, size_t size) {
return VirtualFree(base, size, MEM_DECOMMIT) != 0;
}
@@ -1605,7 +1609,7 @@
// convention.
static unsigned int __stdcall ThreadEntry(void* arg) {
Thread* thread = reinterpret_cast<Thread*>(arg);
- thread->Run();
+ thread->NotifyStartedAndRun();
return 0;
}
@@ -1622,7 +1626,8 @@
// handle until it is started.
Thread::Thread(const Options& options)
- : stack_size_(options.stack_size()) {
+ : stack_size_(options.stack_size()),
+ start_semaphore_(NULL) {
data_ = new PlatformData(kNoThread);
set_name(options.name());
}
@@ -1970,141 +1975,6 @@
}
-// ----------------------------------------------------------------------------
-// Win32 profiler support.
-
-class Sampler::PlatformData : public Malloced {
- public:
- // Get a handle to the calling thread. This is the thread that we are
- // going to profile. We need to make a copy of the handle because we are
- // going to use it in the sampler thread. Using GetThreadHandle() will
- // not work in this case. We're using OpenThread because DuplicateHandle
- // for some reason doesn't work in Chrome's sandbox.
- PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
- THREAD_SUSPEND_RESUME |
- THREAD_QUERY_INFORMATION,
- false,
- GetCurrentThreadId())) {}
-
- ~PlatformData() {
- if (profiled_thread_ != NULL) {
- CloseHandle(profiled_thread_);
- profiled_thread_ = NULL;
- }
- }
-
- HANDLE profiled_thread() { return profiled_thread_; }
-
- private:
- HANDLE profiled_thread_;
-};
-
-
-class SamplerThread : public Thread {
- public:
- static const int kSamplerThreadStackSize = 64 * KB;
-
- explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- instance_ = new SamplerThread(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- } else {
- if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
- }
- OS::Sleep(interval_);
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
- if (!sampler->isolate()->IsInitialized()) return;
- if (!sampler->IsProfiling()) return;
- SamplerThread* sampler_thread =
- reinterpret_cast<SamplerThread*>(raw_sampler_thread);
- sampler_thread->SampleContext(sampler);
- }
-
- void SampleContext(Sampler* sampler) {
- HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
- if (profiled_thread == NULL) return;
-
- // Context used for sampling the register state of the profiled thread.
- CONTEXT context;
- memset(&context, 0, sizeof(context));
-
- Isolate* isolate = sampler->isolate();
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
- if (SuspendThread(profiled_thread) == kSuspendFailed) return;
- sample->state = isolate->current_vm_state();
-
- context.ContextFlags = CONTEXT_FULL;
- if (GetThreadContext(profiled_thread, &context) != 0) {
-#if V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(context.Rip);
- sample->sp = reinterpret_cast<Address>(context.Rsp);
- sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
- sample->pc = reinterpret_cast<Address>(context.Eip);
- sample->sp = reinterpret_cast<Address>(context.Esp);
- sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
- sampler->SampleStack(sample);
- sampler->Tick(sample);
- }
- ResumeThread(profiled_thread);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SamplerThread* instance_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -2114,44 +1984,12 @@
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srand(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SamplerThread::SetUp();
}
void OS::TearDown() {
- SamplerThread::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SamplerThread::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform.h b/src/platform.h
index f2a228c..ab75d74 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -91,8 +91,10 @@
#endif // _MSC_VER
+#ifndef __CYGWIN__
// Random is missing on both Visual Studio and MinGW.
int random();
+#endif
#endif // WIN32
@@ -105,14 +107,6 @@
namespace v8 {
namespace internal {
-// Use AtomicWord for a machine-sized pointer. It is assumed that
-// reads and writes of naturally aligned values of this type are atomic.
-#if defined(__OpenBSD__) && defined(__i386__)
-typedef Atomic32 AtomicWord;
-#else
-typedef intptr_t AtomicWord;
-#endif
-
class Semaphore;
class Mutex;
@@ -337,17 +331,27 @@
static void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value);
#if defined(V8_TARGET_ARCH_IA32)
- // Copy memory area to disjoint memory area.
- static void MemCopy(void* dest, const void* src, size_t size);
// Limit below which the extra overhead of the MemCopy function is likely
// to outweigh the benefits of faster copying.
static const int kMinComplexMemCopy = 64;
- typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
+ // Copy memory area. No restrictions.
+ static void MemMove(void* dest, const void* src, size_t size);
+ typedef void (*MemMoveFunction)(void* dest, const void* src, size_t size);
+
+ // Keep the distinction of "move" vs. "copy" for the benefit of other
+ // architectures.
+ static void MemCopy(void* dest, const void* src, size_t size) {
+ MemMove(dest, src, size);
+ }
#else // V8_TARGET_ARCH_IA32
+ // Copy memory area to disjoint memory area.
static void MemCopy(void* dest, const void* src, size_t size) {
memcpy(dest, src, size);
}
+ static void MemMove(void* dest, const void* src, size_t size) {
+ memmove(dest, src, size);
+ }
static const int kMinComplexMemCopy = 16 * kPointerSize;
#endif // V8_TARGET_ARCH_IA32
@@ -453,6 +457,59 @@
// ----------------------------------------------------------------------------
+// Semaphore
+//
+// A semaphore object is a synchronization object that maintains a count. The
+// count is decremented each time a thread completes a wait for the semaphore
+// object and incremented each time a thread signals the semaphore. When the
+// count reaches zero, threads waiting for the semaphore blocks until the
+// count becomes non-zero.
+
+class Semaphore {
+ public:
+ virtual ~Semaphore() {}
+
+ // Suspends the calling thread until the semaphore counter is non zero
+ // and then decrements the semaphore counter.
+ virtual void Wait() = 0;
+
+ // Suspends the calling thread until the counter is non zero or the timeout
+ // time has passed. If timeout happens the return value is false and the
+ // counter is unchanged. Otherwise the semaphore counter is decremented and
+ // true is returned. The timeout value is specified in microseconds.
+ virtual bool Wait(int timeout) = 0;
+
+ // Increments the semaphore counter.
+ virtual void Signal() = 0;
+};
+
+template <int InitialValue>
+struct CreateSemaphoreTrait {
+ static Semaphore* Create() {
+ return OS::CreateSemaphore(InitialValue);
+ }
+};
+
+// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
+// Usage:
+// // The following semaphore starts at 0.
+// static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
+//
+// void my_function() {
+// // Do something with my_semaphore.Pointer().
+// }
+//
+template <int InitialValue>
+struct LazySemaphore {
+ typedef typename LazyDynamicInstance<
+ Semaphore, CreateSemaphoreTrait<InitialValue>,
+ ThreadSafeInitOnceTrait>::type type;
+};
+
+#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
+
+
+// ----------------------------------------------------------------------------
// Thread
//
// Thread objects are used for creating and running threads. When the start()
@@ -489,9 +546,18 @@
explicit Thread(const Options& options);
virtual ~Thread();
- // Start new thread by calling the Run() method in the new thread.
+ // Start new thread by calling the Run() method on the new thread.
void Start();
+ // Start new thread and wait until Run() method is called on the new thread.
+ void StartSynchronously() {
+ start_semaphore_ = OS::CreateSemaphore(0);
+ Start();
+ start_semaphore_->Wait();
+ delete start_semaphore_;
+ start_semaphore_ = NULL;
+ }
+
// Wait until thread terminates.
void Join();
@@ -541,6 +607,11 @@
class PlatformData;
PlatformData* data() { return data_; }
+ void NotifyStartedAndRun() {
+ if (start_semaphore_) start_semaphore_->Signal();
+ Run();
+ }
+
private:
void set_name(const char* name);
@@ -548,6 +619,7 @@
char name_[kMaxThreadNameLength];
int stack_size_;
+ Semaphore* start_semaphore_;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
@@ -620,59 +692,6 @@
// ----------------------------------------------------------------------------
-// Semaphore
-//
-// A semaphore object is a synchronization object that maintains a count. The
-// count is decremented each time a thread completes a wait for the semaphore
-// object and incremented each time a thread signals the semaphore. When the
-// count reaches zero, threads waiting for the semaphore blocks until the
-// count becomes non-zero.
-
-class Semaphore {
- public:
- virtual ~Semaphore() {}
-
- // Suspends the calling thread until the semaphore counter is non zero
- // and then decrements the semaphore counter.
- virtual void Wait() = 0;
-
- // Suspends the calling thread until the counter is non zero or the timeout
- // time has passed. If timeout happens the return value is false and the
- // counter is unchanged. Otherwise the semaphore counter is decremented and
- // true is returned. The timeout value is specified in microseconds.
- virtual bool Wait(int timeout) = 0;
-
- // Increments the semaphore counter.
- virtual void Signal() = 0;
-};
-
-template <int InitialValue>
-struct CreateSemaphoreTrait {
- static Semaphore* Create() {
- return OS::CreateSemaphore(InitialValue);
- }
-};
-
-// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
-// Usage:
-// // The following semaphore starts at 0.
-// static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
-//
-// void my_function() {
-// // Do something with my_semaphore.Pointer().
-// }
-//
-template <int InitialValue>
-struct LazySemaphore {
- typedef typename LazyDynamicInstance<
- Semaphore, CreateSemaphoreTrait<InitialValue>,
- ThreadSafeInitOnceTrait>::type type;
-};
-
-#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
-
-
-// ----------------------------------------------------------------------------
// Socket
//
@@ -712,96 +731,6 @@
};
-// ----------------------------------------------------------------------------
-// Sampler
-//
-// A sampler periodically samples the state of the VM and optionally
-// (if used for profiling) the program counter and stack pointer for
-// the thread that created it.
-
-// TickSample captures the information collected for each sample.
-class TickSample {
- public:
- TickSample()
- : state(OTHER),
- pc(NULL),
- sp(NULL),
- fp(NULL),
- tos(NULL),
- frames_count(0),
- has_external_callback(false) {}
- StateTag state; // The state of the VM.
- Address pc; // Instruction pointer.
- Address sp; // Stack pointer.
- Address fp; // Frame pointer.
- union {
- Address tos; // Top stack value (*sp).
- Address external_callback;
- };
- static const int kMaxFramesCount = 64;
- Address stack[kMaxFramesCount]; // Call stack.
- int frames_count : 8; // Number of captured frames.
- bool has_external_callback : 1;
-};
-
-class Sampler {
- public:
- // Initialize sampler.
- Sampler(Isolate* isolate, int interval);
- virtual ~Sampler();
-
- int interval() const { return interval_; }
-
- // Performs stack sampling.
- void SampleStack(TickSample* sample) {
- DoSampleStack(sample);
- IncSamplesTaken();
- }
-
- // This method is called for each sampling period with the current
- // program counter.
- virtual void Tick(TickSample* sample) = 0;
-
- // Start and stop sampler.
- void Start();
- void Stop();
-
- // Is the sampler used for profiling?
- bool IsProfiling() const { return NoBarrier_Load(&profiling_) > 0; }
- void IncreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, 1); }
- void DecreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, -1); }
-
- // Whether the sampler is running (that is, consumes resources).
- bool IsActive() const { return NoBarrier_Load(&active_); }
-
- Isolate* isolate() { return isolate_; }
-
- // Used in tests to make sure that stack sampling is performed.
- int samples_taken() const { return samples_taken_; }
- void ResetSamplesTaken() { samples_taken_ = 0; }
-
- class PlatformData;
- PlatformData* data() { return data_; }
-
- PlatformData* platform_data() { return data_; }
-
- protected:
- virtual void DoSampleStack(TickSample* sample) = 0;
-
- private:
- void SetActive(bool value) { NoBarrier_Store(&active_, value); }
- void IncSamplesTaken() { if (++samples_taken_ < 0) samples_taken_ = 0; }
-
- Isolate* isolate_;
- const int interval_;
- Atomic32 profiling_;
- Atomic32 active_;
- PlatformData* data_; // Platform specific data.
- int samples_taken_; // Counts stack samples taken.
- DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
-};
-
-
} } // namespace v8::internal
#endif // V8_PLATFORM_H_
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index d0425b4..287ad66 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -95,7 +95,7 @@
Vector<unsigned> data = Vector<unsigned>::New(total_size);
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
preamble_[PreparseDataConstants::kSymbolCountOffset] = 0;
- memcpy(data.start(), preamble_, sizeof(preamble_));
+ OS::MemCopy(data.start(), preamble_, sizeof(preamble_));
int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
if (function_size > 0) {
function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
@@ -151,7 +151,7 @@
Vector<unsigned> data = Vector<unsigned>::New(total_size);
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
preamble_[PreparseDataConstants::kSymbolCountOffset] = symbol_id_;
- memcpy(data.start(), preamble_, sizeof(preamble_));
+ OS::MemCopy(data.start(), preamble_, sizeof(preamble_));
int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
if (function_size > 0) {
function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index 6e8556a..462dfe2 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -100,9 +100,9 @@
// Hit the bottom of the allocated pushback buffer.
// Double the buffer and continue.
uc16* new_buffer = NewArray<uc16>(pushback_buffer_backing_size_ * 2);
- memcpy(new_buffer + pushback_buffer_backing_size_,
- pushback_buffer_backing_,
- pushback_buffer_backing_size_);
+ OS::MemCopy(new_buffer + pushback_buffer_backing_size_,
+ pushback_buffer_backing_,
+ pushback_buffer_backing_size_);
DeleteArray(pushback_buffer_backing_);
buffer_cursor_ = new_buffer + pushback_buffer_backing_size_;
pushback_buffer_backing_ = pushback_buffer_ = new_buffer;
@@ -168,16 +168,6 @@
unsigned pushback_buffer_backing_size_;
};
-
-// Functions declared by allocation.h and implemented in both api.cc (for v8)
-// or here (for a stand-alone preparser).
-
-void FatalProcessOutOfMemory(const char* reason) {
- V8_Fatal(__FILE__, __LINE__, reason);
-}
-
-bool EnableSlowAsserts() { return true; }
-
} // namespace internal.
@@ -191,11 +181,9 @@
internal::Scanner scanner(&unicode_cache);
scanner.Initialize(&buffer);
internal::CompleteParserRecorder recorder;
- preparser::PreParser::PreParseResult result =
- preparser::PreParser::PreParseProgram(&scanner,
- &recorder,
- internal::kAllowLazy,
- stack_limit);
+ preparser::PreParser preparser(&scanner, &recorder, stack_limit);
+ preparser.set_allow_lazy(true);
+ preparser::PreParser::PreParseResult result = preparser.PreParseProgram();
if (result == preparser::PreParser::kPreParseStackOverflow) {
return PreParserData::StackOverflow();
}
@@ -206,9 +194,3 @@
}
} // namespace v8.
-
-
-// Used by ASSERT macros and other immediate exits.
-extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
- exit(EXIT_FAILURE);
-}
diff --git a/src/preparser.cc b/src/preparser.cc
index c61a08d..6e8800e 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -179,7 +179,7 @@
Statement statement = ParseSourceElement(CHECK_OK);
if (allow_directive_prologue) {
if (statement.IsUseStrictLiteral()) {
- set_language_mode(harmony_scoping_ ?
+ set_language_mode(allow_harmony_scoping() ?
i::EXTENDED_MODE : i::STRICT_MODE);
} else if (!statement.IsStringLiteral()) {
allow_directive_prologue = false;
diff --git a/src/preparser.h b/src/preparser.h
index ce9aa75..e3a036f 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -119,11 +119,7 @@
PreParser(i::Scanner* scanner,
i::ParserRecorder* log,
- uintptr_t stack_limit,
- bool allow_lazy,
- bool allow_natives_syntax,
- bool allow_modules,
- bool allow_generators)
+ uintptr_t stack_limit)
: scanner_(scanner),
log_(log),
scope_(NULL),
@@ -131,30 +127,43 @@
strict_mode_violation_location_(i::Scanner::Location::invalid()),
strict_mode_violation_type_(NULL),
stack_overflow_(false),
- allow_lazy_(allow_lazy),
- allow_modules_(allow_modules),
- allow_natives_syntax_(allow_natives_syntax),
- allow_generators_(allow_generators),
- parenthesized_function_(false),
- harmony_scoping_(scanner->HarmonyScoping()) { }
+ allow_lazy_(false),
+ allow_natives_syntax_(false),
+ allow_generators_(false),
+ parenthesized_function_(false) { }
~PreParser() {}
+ bool allow_natives_syntax() const { return allow_natives_syntax_; }
+ bool allow_lazy() const { return allow_lazy_; }
+ bool allow_modules() const { return scanner_->HarmonyModules(); }
+ bool allow_harmony_scoping() const { return scanner_->HarmonyScoping(); }
+ bool allow_generators() const { return allow_generators_; }
+
+ void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
+ void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
+ void set_allow_modules(bool allow) { scanner_->SetHarmonyModules(allow); }
+ void set_allow_harmony_scoping(bool allow) {
+ scanner_->SetHarmonyScoping(allow);
+ }
+ void set_allow_generators(bool allow) { allow_generators_ = allow; }
+
// Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully
// captured the syntax error), and false if a stack-overflow happened
// during parsing.
- static PreParseResult PreParseProgram(i::Scanner* scanner,
- i::ParserRecorder* log,
- int flags,
- uintptr_t stack_limit) {
- bool allow_lazy = (flags & i::kAllowLazy) != 0;
- bool allow_natives_syntax = (flags & i::kAllowNativesSyntax) != 0;
- bool allow_modules = (flags & i::kAllowModules) != 0;
- bool allow_generators = (flags & i::kAllowGenerators) != 0;
- return PreParser(scanner, log, stack_limit, allow_lazy,
- allow_natives_syntax, allow_modules,
- allow_generators).PreParse();
+ PreParseResult PreParseProgram() {
+ Scope top_scope(&scope_, kTopLevelScope);
+ bool ok = true;
+ int start_position = scanner_->peek_location().beg_pos;
+ ParseSourceElements(i::Token::EOS, &ok);
+ if (stack_overflow_) return kPreParseStackOverflow;
+ if (!ok) {
+ ReportUnexpectedToken(scanner_->current_token());
+ } else if (!scope_->is_classic_mode()) {
+ CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
+ }
+ return kPreParseSuccess;
}
// Parses a single function literal, from the opening parentheses before
@@ -514,22 +523,6 @@
bool is_generator_;
};
- // Preparse the program. Only called in PreParseProgram after creating
- // the instance.
- PreParseResult PreParse() {
- Scope top_scope(&scope_, kTopLevelScope);
- bool ok = true;
- int start_position = scanner_->peek_location().beg_pos;
- ParseSourceElements(i::Token::EOS, &ok);
- if (stack_overflow_) return kPreParseStackOverflow;
- if (!ok) {
- ReportUnexpectedToken(scanner_->current_token());
- } else if (!scope_->is_classic_mode()) {
- CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
- }
- return kPreParseSuccess;
- }
-
// Report syntax error
void ReportUnexpectedToken(i::Token::Value token);
void ReportMessageAt(i::Scanner::Location location,
@@ -683,11 +676,9 @@
const char* strict_mode_violation_type_;
bool stack_overflow_;
bool allow_lazy_;
- bool allow_modules_;
bool allow_natives_syntax_;
bool allow_generators_;
bool parenthesized_function_;
- bool harmony_scoping_;
};
} } // v8::preparser
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index 50a71ce..4660c0f 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -505,7 +505,7 @@
const int slack = 32;
int new_size = size_ + (size_ >> 1) + slack;
char* new_output = NewArray<char>(new_size);
- memcpy(new_output, output_, pos_);
+ OS::MemCopy(new_output, output_, pos_);
DeleteArray(output_);
output_ = new_output;
size_ = new_size;
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index ce07213..eacabef 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -894,20 +894,12 @@
if (sample.pc != NULL) {
*entry++ = code_map_.FindEntry(sample.pc);
- if (sample.has_external_callback) {
+ if (sample.external_callback) {
// Don't use PC when in external callback code, as it can point
// inside callback's code, and we will erroneously report
// that a callback calls itself.
*(entries.start()) = NULL;
*entry++ = code_map_.FindEntry(sample.external_callback);
- } else if (sample.tos != NULL) {
- // Find out, if top of stack was pointing inside a JS function
- // meaning that we have encountered a frameless invocation.
- *entry = code_map_.FindEntry(sample.tos);
- if (*entry != NULL && !(*entry)->is_js_function()) {
- *entry = NULL;
- }
- entry++;
}
for (const Address* stack_pos = sample.stack,
diff --git a/src/proxy.js b/src/proxy.js
index b16de01..528c47d 100644
--- a/src/proxy.js
+++ b/src/proxy.js
@@ -27,9 +27,13 @@
"use strict";
-global.Proxy = new $Object();
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Object = global.Object;
-var $Proxy = global.Proxy
+var $Proxy = new $Object();
+
+// -------------------------------------------------------------------
function ProxyCreate(handler, proto) {
if (!IS_SPEC_OBJECT(handler))
@@ -62,16 +66,26 @@
handler, callTrap, constructTrap, $Function.prototype)
}
-%CheckIsBootstrapping()
-InstallFunctions($Proxy, DONT_ENUM, [
- "create", ProxyCreate,
- "createFunction", ProxyCreateFunction
-])
+
+// -------------------------------------------------------------------
+
+function SetUpProxy() {
+ %CheckIsBootstrapping()
+
+ global.Proxy = $Proxy;
+
+ // Set up non-enumerable properties of the Proxy object.
+ InstallFunctions($Proxy, DONT_ENUM, [
+ "create", ProxyCreate,
+ "createFunction", ProxyCreateFunction
+ ])
+}
+
+SetUpProxy();
-////////////////////////////////////////////////////////////////////////////////
-// Builtins
-////////////////////////////////////////////////////////////////////////////////
+// -------------------------------------------------------------------
+// Proxy Builtins
function DerivedConstructTrap(callTrap) {
return function() {
diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc
index 16766ca..e678d60 100644
--- a/src/regexp-macro-assembler-irregexp.cc
+++ b/src/regexp-macro-assembler-irregexp.cc
@@ -479,7 +479,7 @@
void RegExpMacroAssemblerIrregexp::Copy(Address a) {
- memcpy(a, buffer_.start(), length());
+ OS::MemCopy(a, buffer_.start(), length());
}
@@ -488,7 +488,7 @@
Vector<byte> old_buffer = buffer_;
buffer_ = Vector<byte>::New(old_buffer.length() * 2);
own_buffer_ = true;
- memcpy(buffer_.start(), old_buffer.start(), old_buffer.length());
+ OS::MemCopy(buffer_.start(), old_buffer.start(), old_buffer.length());
if (old_buffer_was_our_own) {
old_buffer.Dispose();
}
diff --git a/src/regexp-stack.cc b/src/regexp-stack.cc
index 325a149..fc4114a 100644
--- a/src/regexp-stack.cc
+++ b/src/regexp-stack.cc
@@ -57,9 +57,7 @@
char* RegExpStack::ArchiveStack(char* to) {
size_t size = sizeof(thread_local_);
- memcpy(reinterpret_cast<void*>(to),
- &thread_local_,
- size);
+ OS::MemCopy(reinterpret_cast<void*>(to), &thread_local_, size);
thread_local_ = ThreadLocal();
return to + size;
}
@@ -67,7 +65,7 @@
char* RegExpStack::RestoreStack(char* from) {
size_t size = sizeof(thread_local_);
- memcpy(&thread_local_, reinterpret_cast<void*>(from), size);
+ OS::MemCopy(&thread_local_, reinterpret_cast<void*>(from), size);
return from + size;
}
@@ -95,10 +93,11 @@
Address new_memory = NewArray<byte>(static_cast<int>(size));
if (thread_local_.memory_size_ > 0) {
// Copy original memory into top of new memory.
- memcpy(reinterpret_cast<void*>(
- new_memory + size - thread_local_.memory_size_),
- reinterpret_cast<void*>(thread_local_.memory_),
- thread_local_.memory_size_);
+ OS::MemCopy(
+ reinterpret_cast<void*>(
+ new_memory + size - thread_local_.memory_size_),
+ reinterpret_cast<void*>(thread_local_.memory_),
+ thread_local_.memory_size_);
DeleteArray(thread_local_.memory_);
}
thread_local_.memory_ = new_memory;
diff --git a/src/regexp.js b/src/regexp.js
index 2349ca7..cb11ad1 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -25,11 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Expect $Object = global.Object;
-// Expect $Array = global.Array;
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Object = global.Object;
+// var $Array = global.Array;
var $RegExp = global.RegExp;
+// -------------------------------------------------------------------
+
// A recursive descent parser for Patterns according to the grammar of
// ECMA-262 15.10.1, with deviations noted below.
function DoConstructRegExp(object, pattern, flags) {
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 2606f8a..752d79c 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -86,17 +86,6 @@
5 * FullCodeGenerator::kBackEdgeDistanceUnit;
-Atomic32 RuntimeProfiler::state_ = 0;
-
-// TODO(isolates): Clean up the semaphore when it is no longer required.
-static LazySemaphore<0>::type semaphore = LAZY_SEMAPHORE_INITIALIZER;
-
-#ifdef DEBUG
-bool RuntimeProfiler::has_been_globally_set_up_ = false;
-#endif
-bool RuntimeProfiler::enabled_ = false;
-
-
RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
: isolate_(isolate),
sampler_threshold_(kSamplerThresholdInit),
@@ -110,15 +99,6 @@
}
-void RuntimeProfiler::GlobalSetUp() {
- ASSERT(!has_been_globally_set_up_);
- enabled_ = V8::UseCrankshaft() && FLAG_opt;
-#ifdef DEBUG
- has_been_globally_set_up_ = true;
-#endif
-}
-
-
static void GetICCounts(JSFunction* function,
int* ic_with_type_info_count,
int* ic_total_count,
@@ -190,23 +170,22 @@
// any back edge in any unoptimized frame will trigger on-stack
// replacement for that frame.
if (FLAG_trace_osr) {
- PrintF("[patching stack checks in ");
+ PrintF("[patching back edges in ");
function->PrintName();
PrintF(" for on-stack replacement]\n");
}
- // Get the stack check stub code object to match against. We aren't
+ // Get the interrupt stub code object to match against. We aren't
// prepared to generate it, but we don't expect to have to.
- Code* stack_check_code = NULL;
+ Code* interrupt_code = NULL;
InterruptStub interrupt_stub;
- bool found_code = interrupt_stub.FindCodeInCache(&stack_check_code, isolate_);
+ bool found_code = interrupt_stub.FindCodeInCache(&interrupt_code, isolate_);
if (found_code) {
Code* replacement_code =
isolate_->builtins()->builtin(Builtins::kOnStackReplacement);
Code* unoptimized_code = shared->code();
- Deoptimizer::PatchStackCheckCode(unoptimized_code,
- stack_check_code,
- replacement_code);
+ Deoptimizer::PatchInterruptCode(
+ unoptimized_code, interrupt_code, replacement_code);
}
}
@@ -296,9 +275,11 @@
function->IsMarkedForParallelRecompilation() ||
function->IsOptimized())) {
int nesting = shared_code->allow_osr_at_loop_nesting_level();
- if (nesting == 0) AttemptOnStackReplacement(function);
- int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
- shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
+ if (nesting < Code::kMaxLoopNestingMarker) {
+ int new_nesting = nesting + 1;
+ shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
+ AttemptOnStackReplacement(function);
+ }
}
// Only record top-level code on top of the execution stack and
@@ -385,13 +366,9 @@
void RuntimeProfiler::SetUp() {
- ASSERT(has_been_globally_set_up_);
if (!FLAG_watch_ic_patching) {
ClearSampleBuffer();
}
- // If the ticker hasn't already started, make sure to do so to get
- // the ticks for the runtime profiler.
- if (IsEnabled()) isolate_->logger()->EnsureTickerStarted();
}
@@ -431,48 +408,6 @@
}
-void RuntimeProfiler::HandleWakeUp(Isolate* isolate) {
- // The profiler thread must still be waiting.
- ASSERT(NoBarrier_Load(&state_) >= 0);
- // In IsolateEnteredJS we have already incremented the counter and
- // undid the decrement done by the profiler thread. Increment again
- // to get the right count of active isolates.
- NoBarrier_AtomicIncrement(&state_, 1);
- semaphore.Pointer()->Signal();
-}
-
-
-bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() {
- Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1);
- ASSERT(old_state >= -1);
- if (old_state != 0) return false;
- semaphore.Pointer()->Wait();
- return true;
-}
-
-
-void RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(Thread* thread) {
- // Do a fake increment. If the profiler is waiting on the semaphore,
- // the returned state is 0, which can be left as an initial state in
- // case profiling is restarted later. If the profiler is not
- // waiting, the increment will prevent it from waiting, but has to
- // be undone after the profiler is stopped.
- Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, 1);
- ASSERT(new_state >= 0);
- if (new_state == 0) {
- // The profiler thread is waiting. Wake it up. It must check for
- // stop conditions before attempting to wait again.
- semaphore.Pointer()->Signal();
- }
- thread->Join();
- // The profiler thread is now stopped. Undo the increment in case it
- // was not waiting.
- if (new_state != 0) {
- NoBarrier_AtomicIncrement(&state_, -1);
- }
-}
-
-
void RuntimeProfiler::RemoveDeadSamples() {
for (int i = 0; i < kSamplerWindowSize; i++) {
Object* function = sampler_window_[i];
diff --git a/src/runtime-profiler.h b/src/runtime-profiler.h
index 62c48c7..1bf9aa8 100644
--- a/src/runtime-profiler.h
+++ b/src/runtime-profiler.h
@@ -43,13 +43,6 @@
public:
explicit RuntimeProfiler(Isolate* isolate);
- static void GlobalSetUp();
-
- static inline bool IsEnabled() {
- ASSERT(has_been_globally_set_up_);
- return enabled_;
- }
-
void OptimizeNow();
void SetUp();
@@ -63,26 +56,6 @@
// Rate limiting support.
- // VM thread interface.
- //
- // Called by isolates when their states change.
- static inline void IsolateEnteredJS(Isolate* isolate);
- static inline void IsolateExitedJS(Isolate* isolate);
-
- // Profiler thread interface.
- //
- // WaitForSomeIsolateToEnterJS():
- // When no isolates are running JavaScript code for some time the
- // profiler thread suspends itself by calling the wait function. The
- // wait function returns true after it waited or false immediately.
- // While the function was waiting the profiler may have been
- // disabled so it *must check* whether it is allowed to continue.
- static bool WaitForSomeIsolateToEnterJS();
-
- // Stops the runtime profiler thread when profiling support is being
- // turned off.
- static void StopRuntimeProfilerThreadBeforeShutdown(Thread* thread);
-
void UpdateSamplesAfterScavenge();
void RemoveDeadSamples();
void UpdateSamplesAfterCompact(ObjectVisitor* visitor);
@@ -92,8 +65,6 @@
private:
static const int kSamplerWindowSize = 16;
- static void HandleWakeUp(Isolate* isolate);
-
void Optimize(JSFunction* function, const char* reason);
void ClearSampleBuffer();
@@ -116,39 +87,8 @@
bool any_ic_changed_;
bool code_generated_;
-
- // Possible state values:
- // -1 => the profiler thread is waiting on the semaphore
- // 0 or positive => the number of isolates running JavaScript code.
- static Atomic32 state_;
-
-#ifdef DEBUG
- static bool has_been_globally_set_up_;
-#endif
- static bool enabled_;
};
-
-// Implementation of RuntimeProfiler inline functions.
-
-void RuntimeProfiler::IsolateEnteredJS(Isolate* isolate) {
- Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, 1);
- if (new_state == 0) {
- // Just incremented from -1 to 0. -1 can only be set by the
- // profiler thread before it suspends itself and starts waiting on
- // the semaphore.
- HandleWakeUp(isolate);
- }
- ASSERT(new_state >= 0);
-}
-
-
-void RuntimeProfiler::IsolateExitedJS(Isolate* isolate) {
- Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, -1);
- ASSERT(new_state >= 0);
- USE(new_state);
-}
-
} } // namespace v8::internal
#endif // V8_RUNTIME_PROFILER_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 78efc8d..7e7d6d5 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -43,6 +43,7 @@
#include "deoptimizer.h"
#include "date.h"
#include "execution.h"
+#include "full-codegen.h"
#include "global-handles.h"
#include "isolate-inl.h"
#include "jsregexp.h"
@@ -60,6 +61,7 @@
#include "string-search.h"
#include "stub-cache.h"
#include "uri.h"
+#include "v8conversions.h"
#include "v8threads.h"
#include "vm-state-inl.h"
@@ -637,19 +639,6 @@
}
-static size_t ArrayBufferAllocatedLength(Isolate* isolate,
- JSArrayBuffer* buffer) {
- NoHandleAllocation hc(isolate);
- Object* byte_length = buffer->byte_length();
- if (byte_length->IsSmi()) {
- return Smi::cast(byte_length)->value();
- } else {
- double value = HeapNumber::cast(byte_length)->value();
- return static_cast<size_t>(value);
- }
-}
-
-
static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
Persistent<Value> object,
void* data) {
@@ -657,8 +646,8 @@
HandleScope scope(isolate);
Handle<Object> internal_object = Utils::OpenHandle(*object);
- size_t allocated_length = ArrayBufferAllocatedLength(
- isolate, JSArrayBuffer::cast(*internal_object));
+ size_t allocated_length = NumberToSize(
+ isolate, JSArrayBuffer::cast(*internal_object)->byte_length());
isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
-static_cast<intptr_t>(allocated_length));
if (data != NULL)
@@ -743,12 +732,12 @@
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
CONVERT_DOUBLE_ARG_CHECKED(first, 2);
size_t start = static_cast<size_t>(first);
- size_t target_length = ArrayBufferAllocatedLength(isolate, *target);
+ size_t target_length = NumberToSize(isolate, target->byte_length());
if (target_length == 0)
return isolate->heap()->undefined_value();
- ASSERT(ArrayBufferAllocatedLength(isolate, *source) - target_length >= start);
+ ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
CopyBytes(target_data, source_data + start, target_length);
@@ -756,6 +745,116 @@
}
+enum TypedArrayId {
+ // arrayIds below should be synchromized with typedarray.js natives.
+ ARRAY_ID_UINT8 = 1,
+ ARRAY_ID_INT8 = 2,
+ ARRAY_ID_UINT16 = 3,
+ ARRAY_ID_INT16 = 4,
+ ARRAY_ID_UINT32 = 5,
+ ARRAY_ID_INT32 = 6,
+ ARRAY_ID_FLOAT32 = 7,
+ ARRAY_ID_FLOAT64 = 8
+};
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 5);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+ CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
+
+ ExternalArrayType arrayType;
+ ElementsKind elementsKind;
+ size_t elementSize;
+ switch (arrayId) {
+ case ARRAY_ID_UINT8:
+ elementsKind = EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+ arrayType = kExternalUnsignedByteArray;
+ elementSize = 1;
+ break;
+ case ARRAY_ID_INT8:
+ elementsKind = EXTERNAL_BYTE_ELEMENTS;
+ arrayType = kExternalByteArray;
+ elementSize = 1;
+ break;
+ case ARRAY_ID_UINT16:
+ elementsKind = EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+ arrayType = kExternalUnsignedShortArray;
+ elementSize = 2;
+ break;
+ case ARRAY_ID_INT16:
+ elementsKind = EXTERNAL_SHORT_ELEMENTS;
+ arrayType = kExternalShortArray;
+ elementSize = 2;
+ break;
+ case ARRAY_ID_UINT32:
+ elementsKind = EXTERNAL_UNSIGNED_INT_ELEMENTS;
+ arrayType = kExternalUnsignedIntArray;
+ elementSize = 4;
+ break;
+ case ARRAY_ID_INT32:
+ elementsKind = EXTERNAL_INT_ELEMENTS;
+ arrayType = kExternalIntArray;
+ elementSize = 4;
+ break;
+ case ARRAY_ID_FLOAT32:
+ elementsKind = EXTERNAL_FLOAT_ELEMENTS;
+ arrayType = kExternalFloatArray;
+ elementSize = 4;
+ break;
+ case ARRAY_ID_FLOAT64:
+ elementsKind = EXTERNAL_DOUBLE_ELEMENTS;
+ arrayType = kExternalDoubleArray;
+ elementSize = 8;
+ break;
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+
+ holder->set_buffer(*buffer);
+ holder->set_byte_offset(*byte_offset_object);
+ holder->set_byte_length(*byte_length_object);
+
+ size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
+ size_t byte_length = NumberToSize(isolate, *byte_length_object);
+ ASSERT(byte_length % elementSize == 0);
+ size_t length = byte_length / elementSize;
+
+ Handle<Object> length_obj =
+ isolate->factory()->NewNumber(static_cast<double>(length));
+ holder->set_length(*length_obj);
+ Handle<ExternalArray> elements =
+ isolate->factory()->NewExternalArray(
+ static_cast<int>(length), arrayType,
+ static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
+ Handle<Map> map =
+ isolate->factory()->GetElementsTransitionMap(holder, elementsKind);
+ holder->set_map(*map);
+ holder->set_elements(*elements);
+ return isolate->heap()->undefined_value();
+}
+
+
+#define TYPED_ARRAY_GETTER(getter, accessor) \
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
+ HandleScope scope(isolate); \
+ ASSERT(args.length() == 1); \
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); \
+ return holder->accessor(); \
+ }
+
+TYPED_ARRAY_GETTER(Buffer, buffer)
+TYPED_ARRAY_GETTER(ByteLength, byte_length)
+TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
+TYPED_ARRAY_GETTER(Length, length)
+
+#undef TYPED_ARRAY_GETTER
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -956,8 +1055,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
- Object* obj = input_obj;
+ CONVERT_ARG_CHECKED(Object, obj, 0);
// We don't expect access checks to be needed on JSProxy objects.
ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
do {
@@ -975,12 +1073,43 @@
}
+static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
+ Object* receiver) {
+ Object* current = receiver->GetPrototype(isolate);
+ while (current->IsJSObject() &&
+ JSObject::cast(current)->map()->is_hidden_prototype()) {
+ current = current->GetPrototype(isolate);
+ }
+ return current;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 2);
- CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(Object, prototype, 1);
- return input_obj->SetPrototype(prototype, true);
+ if (FLAG_harmony_observation && obj->map()->is_observed()) {
+ HandleScope scope(isolate);
+ Handle<JSObject> receiver(obj);
+ Handle<Object> value(prototype, isolate);
+ Handle<Object> old_value(
+ GetPrototypeSkipHiddenPrototypes(isolate, *receiver), isolate);
+
+ MaybeObject* result = receiver->SetPrototype(*value, true);
+ Handle<Object> hresult;
+ if (!result->ToHandle(&hresult, isolate)) return result;
+
+ Handle<Object> new_value(
+ GetPrototypeSkipHiddenPrototypes(isolate, *receiver), isolate);
+ if (!new_value->SameValue(*old_value)) {
+ JSObject::EnqueueChangeRecord(receiver, "prototype",
+ isolate->factory()->proto_string(),
+ old_value);
+ }
+ return *hresult;
+ }
+ return obj->SetPrototype(prototype, true);
}
@@ -1918,6 +2047,24 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) {
+ NoHandleAllocation ha(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
+ if (!callable->IsJSFunction()) {
+ HandleScope scope(isolate);
+ bool threw = false;
+ Handle<Object> delegate =
+ Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
+ if (threw) return Failure::Exception();
+ callable = JSFunction::cast(*delegate);
+ }
+ JSFunction* function = JSFunction::cast(callable);
+ SharedFunctionInfo* shared = function->shared();
+ return isolate->heap()->ToBoolean(shared->is_classic_mode());
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 1);
@@ -2243,6 +2390,31 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) {
+ NoHandleAllocation ha(isolate);
+ ASSERT(args.length() == 0);
+ JavaScriptFrameIterator it(isolate);
+ JavaScriptFrame* frame = it.frame();
+ JSFunction* function = JSFunction::cast(frame->function());
+ RUNTIME_ASSERT(function->shared()->is_generator());
+
+ JSGeneratorObject* generator;
+ if (frame->IsConstructor()) {
+ generator = JSGeneratorObject::cast(frame->receiver());
+ } else {
+ MaybeObject* maybe_generator =
+ isolate->heap()->AllocateJSGeneratorObject(function);
+ if (!maybe_generator->To(&generator)) return maybe_generator;
+ }
+ generator->set_function(function);
+ generator->set_context(isolate->heap()->undefined_value());
+ generator->set_continuation(0);
+ generator->set_operand_stack(isolate->heap()->empty_fixed_array());
+
+ return generator;
+}
+
+
MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
Object* char_code) {
uint32_t code;
@@ -3898,6 +4070,33 @@
}
+MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
+ Handle<JSReceiver> object,
+ Handle<Object> key) {
+ HandleScope scope(isolate);
+
+ // Check if the given key is an array index.
+ uint32_t index;
+ if (key->ToArrayIndex(&index)) {
+ return isolate->heap()->ToBoolean(object->HasElement(index));
+ }
+
+ // Convert the key to a name - possibly by calling back into JavaScript.
+ Handle<Name> name;
+ if (key->IsName()) {
+ name = Handle<Name>::cast(key);
+ } else {
+ bool has_pending_exception = false;
+ Handle<Object> converted =
+ Execution::ToString(key, &has_pending_exception);
+ if (has_pending_exception) return Failure::Exception();
+ name = Handle<Name>::cast(converted);
+ }
+
+ return isolate->heap()->ToBoolean(object->HasProperty(*name));
+}
+
+
MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
Handle<Object> object,
Handle<Object> key) {
@@ -4109,14 +4308,6 @@
if (callback->IsAccessorInfo()) {
return isolate->heap()->undefined_value();
}
- // TODO(mstarzinger): The __proto__ property should actually be a real
- // JavaScript accessor instead of a foreign callback. But for now we just
- // avoid changing the writability and configurability attribute of this
- // property.
- Handle<Name> proto_string = isolate->factory()->proto_string();
- if (callback->IsForeign() && proto_string->Equals(*name)) {
- attr = static_cast<PropertyAttributes>(attr & ~(READ_ONLY | DONT_DELETE));
- }
// Avoid redefining foreign callback as data property, just use the stored
// setter to update the value instead.
// TODO(mstarzinger): So far this only works if property attributes don't
@@ -4323,9 +4514,10 @@
}
-MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<Object> key) {
+MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<Object> key,
+ JSReceiver::DeleteMode mode) {
HandleScope scope(isolate);
// Check if the given key is an array index.
@@ -4341,7 +4533,7 @@
return isolate->heap()->true_value();
}
- return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
+ return receiver->DeleteElement(index, mode);
}
Handle<Name> name;
@@ -4356,7 +4548,7 @@
}
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
- return receiver->DeleteProperty(*name, JSReceiver::FORCE_DELETION);
+ return receiver->DeleteProperty(*name, mode);
}
@@ -4607,7 +4799,8 @@
// Fast case: either the key is a real named property or it is not
// an array index and there are no interceptors or hidden
// prototypes.
- if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
+ if (object->HasRealNamedProperty(isolate, key))
+ return isolate->heap()->true_value();
Map* map = object->map();
if (!key_is_array_index &&
!map->has_named_interceptor() &&
@@ -7568,9 +7761,10 @@
unoptimized->kind() == Code::FUNCTION) {
CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
- isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
- unoptimized->set_allow_osr_at_loop_nesting_level(
- Code::kMaxLoopNestingMarker);
+ for (int i = 0; i <= Code::kMaxLoopNestingMarker; i++) {
+ unoptimized->set_allow_osr_at_loop_nesting_level(i);
+ isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
+ }
} else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("parallel"))) {
function->MarkForParallelRecompilation();
}
@@ -7663,25 +7857,28 @@
ASSERT(frame->LookupCode() == *unoptimized);
ASSERT(unoptimized->contains(frame->pc()));
- // Use linear search of the unoptimized code's stack check table to find
+ // Use linear search of the unoptimized code's back edge table to find
// the AST id matching the PC.
Address start = unoptimized->instruction_start();
unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
- Address table_cursor = start + unoptimized->stack_check_table_offset();
+ Address table_cursor = start + unoptimized->back_edge_table_offset();
uint32_t table_length = Memory::uint32_at(table_cursor);
table_cursor += kIntSize;
+ uint8_t loop_depth = 0;
for (unsigned i = 0; i < table_length; ++i) {
// Table entries are (AST id, pc offset) pairs.
uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
if (pc_offset == target_pc_offset) {
ast_id = BailoutId(static_cast<int>(Memory::uint32_at(table_cursor)));
+ loop_depth = Memory::uint8_at(table_cursor + 2 * kIntSize);
break;
}
- table_cursor += 2 * kIntSize;
+ table_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
ASSERT(!ast_id.IsNone());
if (FLAG_trace_osr) {
- PrintF("[replacing on-stack at AST id %d in ", ast_id.ToInt());
+ PrintF("[replacing on-stack at AST id %d, loop depth %d in ",
+ ast_id.ToInt(), loop_depth);
function->PrintName();
PrintF("]\n");
}
@@ -7709,18 +7906,18 @@
}
}
- // Revert to the original stack checks in the original unoptimized code.
+ // Revert to the original interrupt calls in the original unoptimized code.
if (FLAG_trace_osr) {
- PrintF("[restoring original stack checks in ");
+ PrintF("[restoring original interrupt calls in ");
function->PrintName();
PrintF("]\n");
}
InterruptStub interrupt_stub;
- Handle<Code> check_code = interrupt_stub.GetCode(isolate);
+ Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
- Deoptimizer::RevertStackCheckCode(*unoptimized,
- *check_code,
- *replacement_code);
+ Deoptimizer::RevertInterruptCode(*unoptimized,
+ *interrupt_code,
+ *replacement_code);
// Allow OSR only at nesting level zero again.
unoptimized->set_allow_osr_at_loop_nesting_level(0);
@@ -8821,14 +9018,18 @@
storage_(Handle<FixedArray>::cast(
isolate->global_handles()->Create(*storage))),
index_offset_(0u),
- fast_elements_(fast_elements) { }
+ fast_elements_(fast_elements),
+ exceeds_array_limit_(false) { }
~ArrayConcatVisitor() {
clear_storage();
}
void visit(uint32_t i, Handle<Object> elm) {
- if (i >= JSObject::kMaxElementCount - index_offset_) return;
+ if (i > JSObject::kMaxElementCount - index_offset_) {
+ exceeds_array_limit_ = true;
+ return;
+ }
uint32_t index = index_offset_ + i;
if (fast_elements_) {
@@ -8863,6 +9064,10 @@
}
}
+ bool exceeds_array_limit() {
+ return exceeds_array_limit_;
+ }
+
Handle<JSArray> ToArray() {
Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
Handle<Object> length =
@@ -8921,7 +9126,8 @@
// Index after last seen index. Always less than or equal to
// JSObject::kMaxElementCount.
uint32_t index_offset_;
- bool fast_elements_;
+ bool fast_elements_ : 1;
+ bool exceeds_array_limit_ : 1;
};
@@ -9477,6 +9683,11 @@
}
}
+ if (visitor.exceeds_array_limit()) {
+ return isolate->Throw(
+ *isolate->factory()->NewRangeError("invalid_array_length",
+ HandleVector<Object>(NULL, 0)));
+ }
return *visitor.ToArray();
}
@@ -10733,14 +10944,14 @@
info.MarkAsEval();
info.SetContext(Handle<Context>(function_->context()));
}
- if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
+ if (Parser::Parse(&info) && Scope::Analyze(&info)) {
scope = info.function()->scope();
}
RetrieveScopeChain(scope, shared_info);
} else {
// Function code
CompilationInfoWithZone info(shared_info);
- if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
+ if (Parser::Parse(&info) && Scope::Analyze(&info)) {
scope = info.function()->scope();
}
RetrieveScopeChain(scope, shared_info);
@@ -12015,11 +12226,8 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 1);
-
CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
- // Use the __proto__ accessor.
- return Accessors::ObjectPrototype.getter(obj, NULL);
+ return GetPrototypeSkipHiddenPrototypes(isolate, obj);
}
@@ -12786,7 +12994,7 @@
String::FlatContent format_content = format->GetFlatContent();
RUNTIME_ASSERT(format_content.IsAscii());
Vector<const uint8_t> chars = format_content.ToOneByteVector();
- LOGGER->LogRuntime(isolate, Vector<const char>::cast(chars), elms);
+ isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms);
return isolate->heap()->undefined_value();
}
diff --git a/src/runtime.h b/src/runtime.h
index b16acd1..cbf70e9 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -64,6 +64,7 @@
F(ToFastProperties, 1, 1) \
F(FinishArrayPrototypeSetup, 1, 1) \
F(SpecialArrayFunctions, 1, 1) \
+ F(IsClassicModeFunction, 1, 1) \
F(GetDefaultReceiver, 1, 1) \
\
F(GetPrototype, 1, 1) \
@@ -218,6 +219,7 @@
F(NumberToExponential, 2, 1) \
F(NumberToPrecision, 2, 1)
+
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
/* Reflection */ \
F(FunctionSetInstanceClassName, 2, 1) \
@@ -294,6 +296,9 @@
F(CreateArrayLiteral, 3, 1) \
F(CreateArrayLiteralShallow, 3, 1) \
\
+ /* Harmony generators */ \
+ F(CreateJSGeneratorObject, 0, 1) \
+ \
/* Harmony modules */ \
F(IsJSModule, 1, 1) \
\
@@ -346,6 +351,12 @@
F(ArrayBufferGetByteLength, 1, 1)\
F(ArrayBufferSliceImpl, 3, 1) \
\
+ F(TypedArrayInitialize, 5, 1) \
+ F(TypedArrayGetBuffer, 1, 1) \
+ F(TypedArrayGetByteLength, 1, 1) \
+ F(TypedArrayGetByteOffset, 1, 1) \
+ F(TypedArrayGetLength, 1, 1) \
+ \
/* Statements */ \
F(NewClosure, 3, 1) \
F(NewObject, 1, 1) \
@@ -698,7 +709,13 @@
Handle<Object> value,
PropertyAttributes attr);
- MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty(
+ MUST_USE_RESULT static MaybeObject* DeleteObjectProperty(
+ Isolate* isolate,
+ Handle<JSReceiver> object,
+ Handle<Object> key,
+ JSReceiver::DeleteMode mode);
+
+ MUST_USE_RESULT static MaybeObject* HasObjectProperty(
Isolate* isolate,
Handle<JSReceiver> object,
Handle<Object> key);
diff --git a/src/sampler.cc b/src/sampler.cc
new file mode 100644
index 0000000..948b054
--- /dev/null
+++ b/src/sampler.cc
@@ -0,0 +1,694 @@
+// Copyright 2013 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.
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
+ || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
+
+#define USE_SIGNALS
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)
+#include <ucontext.h>
+#endif
+#include <unistd.h>
+
+// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
+// Old versions of the C library <signal.h> didn't define the type.
+#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
+ defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
+#include <asm/sigcontext.h>
+#endif
+
+#elif defined(__MACH__)
+
+#include <mach/mach.h>
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+#include "win32-headers.h"
+
+#endif
+
+#include "v8.h"
+
+#include "frames-inl.h"
+#include "log.h"
+#include "platform.h"
+#include "simulator.h"
+#include "v8threads.h"
+
+
+#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
+
+// Not all versions of Android's C library provide ucontext_t.
+// Detect this and provide custom but compatible definitions. Note that these
+// follow the GLibc naming convention to access register values from
+// mcontext_t.
+//
+// See http://code.google.com/p/android/issues/detail?id=34784
+
+#if defined(__arm__)
+
+typedef struct sigcontext mcontext_t;
+
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+
+#elif defined(__mips__)
+// MIPS version of sigcontext, for Android bionic.
+typedef struct {
+ uint32_t regmask;
+ uint32_t status;
+ uint64_t pc;
+ uint64_t gregs[32];
+ uint64_t fpregs[32];
+ uint32_t acx;
+ uint32_t fpc_csr;
+ uint32_t fpc_eir;
+ uint32_t used_math;
+ uint32_t dsp;
+ uint64_t mdhi;
+ uint64_t mdlo;
+ uint32_t hi1;
+ uint32_t lo1;
+ uint32_t hi2;
+ uint32_t lo2;
+ uint32_t hi3;
+ uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+
+#elif defined(__i386__)
+// x86 version for Android.
+typedef struct {
+ uint32_t gregs[19];
+ void* fpregs;
+ uint32_t oldmask;
+ uint32_t cr2;
+} mcontext_t;
+
+typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
+#endif
+
+#endif // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
+
+
+namespace v8 {
+namespace internal {
+
+#if defined(USE_SIGNALS)
+
+class Sampler::PlatformData : public Malloced {
+ public:
+ PlatformData()
+ : vm_tid_(pthread_self()),
+ profiled_thread_id_(ThreadId::Current()) {}
+
+ pthread_t vm_tid() const { return vm_tid_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+ pthread_t vm_tid_;
+ ThreadId profiled_thread_id_;
+};
+
+
+class SignalHandler : public AllStatic {
+ public:
+ static inline void EnsureInstalled() {
+ if (signal_handler_installed_) return;
+ struct sigaction sa;
+ sa.sa_sigaction = &HandleProfilerSignal;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ signal_handler_installed_ =
+ (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
+ }
+
+ static inline void Restore() {
+ if (signal_handler_installed_) {
+ sigaction(SIGPROF, &old_signal_handler_, 0);
+ signal_handler_installed_ = false;
+ }
+ }
+
+ static inline bool Installed() {
+ return signal_handler_installed_;
+ }
+
+ private:
+ static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
+ static bool signal_handler_installed_;
+ static struct sigaction old_signal_handler_;
+};
+
+struct sigaction SignalHandler::old_signal_handler_;
+bool SignalHandler::signal_handler_installed_ = false;
+
+
+void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
+ void* context) {
+#if defined(__native_client__)
+ // As Native Client does not support signal handling, profiling
+ // is disabled.
+ return;
+#else
+ USE(info);
+ if (signal != SIGPROF) return;
+ Isolate* isolate = Isolate::UncheckedCurrent();
+ if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
+ // We require a fully initialized and entered isolate.
+ return;
+ }
+ if (v8::Locker::IsActive() &&
+ !isolate->thread_manager()->IsLockedByCurrentThread()) {
+ return;
+ }
+
+ Sampler* sampler = isolate->logger()->sampler();
+ if (sampler == NULL || !sampler->IsActive()) return;
+
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ if (sample == NULL) sample = &sample_obj;
+
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif // V8_TARGET_ARCH_*
+#else
+ // Extracting the sample from the context is extremely machine dependent.
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+ mcontext_t& mcontext = ucontext->uc_mcontext;
+ sample->state = isolate->current_vm_state();
+#if defined(__linux__) || defined(__ANDROID__)
+#if V8_HOST_ARCH_IA32
+ sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
+ sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
+ sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
+#elif V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
+ sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
+ sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
+#elif V8_HOST_ARCH_ARM
+#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
+ (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+ // Old GLibc ARM versions used a gregs[] array to access the register
+ // values from mcontext_t.
+ sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
+ sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
+ sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
+#else
+ sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
+ sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
+ sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
+#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
+ // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#elif V8_HOST_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(mcontext.pc);
+ sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
+ sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
+#endif // V8_HOST_ARCH_*
+#elif defined(__FreeBSD__)
+#if V8_HOST_ARCH_IA32
+ sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
+ sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
+ sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
+#elif V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
+ sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
+ sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
+#elif V8_HOST_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
+ sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
+ sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
+#endif // V8_HOST_ARCH_*
+#elif defined(__NetBSD__)
+#if V8_HOST_ARCH_IA32
+ sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
+ sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
+ sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
+#elif V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
+ sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
+ sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
+#endif // V8_HOST_ARCH_*
+#elif defined(__OpenBSD__)
+ USE(mcontext);
+#if V8_HOST_ARCH_IA32
+ sample->pc = reinterpret_cast<Address>(ucontext->sc_eip);
+ sample->sp = reinterpret_cast<Address>(ucontext->sc_esp);
+ sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp);
+#elif V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
+ sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
+ sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
+#endif // V8_HOST_ARCH_*
+#elif defined(__sun)
+ sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
+ sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
+ sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
+#endif // __sun
+#endif // USE_SIMULATOR
+
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+#endif // __native_client__
+}
+
+#elif defined(__MACH__)
+class Sampler::PlatformData : public Malloced {
+ public:
+ PlatformData()
+ : profiled_thread_(mach_thread_self()),
+ profiled_thread_id_(ThreadId::Current()) {}
+
+ ~PlatformData() {
+ // Deallocate Mach port for thread.
+ mach_port_deallocate(mach_task_self(), profiled_thread_);
+ }
+
+ thread_act_t profiled_thread() { return profiled_thread_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+ // Note: for profiled_thread_ Mach primitives are used instead of PThread's
+ // because the latter doesn't provide thread manipulation primitives required.
+ // For details, consult "Mac OS X Internals" book, Section 7.3.
+ thread_act_t profiled_thread_;
+ ThreadId profiled_thread_id_;
+};
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+// ----------------------------------------------------------------------------
+// Win32 profiler support. On Cygwin we use the same sampler implementation as
+// on Win32.
+
+class Sampler::PlatformData : public Malloced {
+ public:
+ // Get a handle to the calling thread. This is the thread that we are
+ // going to profile. We need to make a copy of the handle because we are
+ // going to use it in the sampler thread. Using GetThreadHandle() will
+ // not work in this case. We're using OpenThread because DuplicateHandle
+ // for some reason doesn't work in Chrome's sandbox.
+ PlatformData()
+ : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+ THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION,
+ false,
+ GetCurrentThreadId())),
+ profiled_thread_id_(ThreadId::Current()) {}
+
+ ~PlatformData() {
+ if (profiled_thread_ != NULL) {
+ CloseHandle(profiled_thread_);
+ profiled_thread_ = NULL;
+ }
+ }
+
+ HANDLE profiled_thread() { return profiled_thread_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+ HANDLE profiled_thread_;
+ ThreadId profiled_thread_id_;
+};
+
+#endif
+
+
+class SamplerThread : public Thread {
+ public:
+ static const int kSamplerThreadStackSize = 64 * KB;
+
+ explicit SamplerThread(int interval)
+ : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
+ interval_(interval) {}
+
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
+
+ static void AddActiveSampler(Sampler* sampler) {
+ bool need_to_start = false;
+ ScopedLock lock(mutex_);
+ if (instance_ == NULL) {
+ // Start a thread that will send SIGPROF signal to VM threads,
+ // when CPU profiling will be enabled.
+ instance_ = new SamplerThread(sampler->interval());
+ need_to_start = true;
+ }
+
+ ASSERT(sampler->IsActive());
+ ASSERT(!instance_->active_samplers_.Contains(sampler));
+ ASSERT(instance_->interval_ == sampler->interval());
+ instance_->active_samplers_.Add(sampler);
+
+#if defined(USE_SIGNALS)
+ SignalHandler::EnsureInstalled();
+#endif
+ if (need_to_start) instance_->StartSynchronously();
+ }
+
+ static void RemoveActiveSampler(Sampler* sampler) {
+ SamplerThread* instance_to_remove = NULL;
+ {
+ ScopedLock lock(mutex_);
+
+ ASSERT(sampler->IsActive());
+ bool removed = instance_->active_samplers_.RemoveElement(sampler);
+ ASSERT(removed);
+ USE(removed);
+
+ // We cannot delete the instance immediately as we need to Join() the
+ // thread but we are holding mutex_ and the thread may try to acquire it.
+ if (instance_->active_samplers_.is_empty()) {
+ instance_to_remove = instance_;
+ instance_ = NULL;
+#if defined(USE_SIGNALS)
+ SignalHandler::Restore();
+#endif
+ }
+ }
+
+ if (!instance_to_remove) return;
+ instance_to_remove->Join();
+ delete instance_to_remove;
+ }
+
+ // Implement Thread::Run().
+ virtual void Run() {
+ while (true) {
+ {
+ ScopedLock lock(mutex_);
+ if (active_samplers_.is_empty()) break;
+ // When CPU profiling is enabled both JavaScript and C++ code is
+ // profiled. We must not suspend.
+ for (int i = 0; i < active_samplers_.length(); ++i) {
+ Sampler* sampler = active_samplers_.at(i);
+ if (!sampler->isolate()->IsInitialized()) continue;
+ if (!sampler->IsProfiling()) continue;
+ SampleContext(sampler);
+ }
+ }
+ OS::Sleep(interval_);
+ }
+ }
+
+ private:
+#if defined(USE_SIGNALS)
+
+ void SampleContext(Sampler* sampler) {
+ if (!SignalHandler::Installed()) return;
+ pthread_t tid = sampler->platform_data()->vm_tid();
+ int result = pthread_kill(tid, SIGPROF);
+ USE(result);
+ ASSERT(result == 0);
+ }
+
+#elif defined(__MACH__)
+
+ void SampleContext(Sampler* sampler) {
+ thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+ Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ if (sample == NULL) sample = &sample_obj;
+
+ if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
+
+#if V8_HOST_ARCH_X64
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+ x86_thread_state64_t state;
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __r ## name
+#else
+#define REGISTER_FIELD(name) r ## name
+#endif // __DARWIN_UNIX03
+#elif V8_HOST_ARCH_IA32
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+ i386_thread_state_t state;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __e ## name
+#else
+#define REGISTER_FIELD(name) e ## name
+#endif // __DARWIN_UNIX03
+#else
+#error Unsupported Mac OS X host architecture.
+#endif // V8_HOST_ARCH
+
+ if (thread_get_state(profiled_thread,
+ flavor,
+ reinterpret_cast<natural_t*>(&state),
+ &count) == KERN_SUCCESS) {
+ sample->state = isolate->current_vm_state();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+ sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+ sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+ sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+#endif // USE_SIMULATOR
+#undef REGISTER_FIELD
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+ }
+ thread_resume(profiled_thread);
+ }
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+ void SampleContext(Sampler* sampler) {
+ HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
+ if (profiled_thread == NULL) return;
+
+ // Context used for sampling the register state of the profiled thread.
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
+
+ Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ if (sample == NULL) sample = &sample_obj;
+
+ static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+ if (SuspendThread(profiled_thread) == kSuspendFailed) return;
+ sample->state = isolate->current_vm_state();
+
+ context.ContextFlags = CONTEXT_FULL;
+ if (GetThreadContext(profiled_thread, &context) != 0) {
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+#if V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(context.Rip);
+ sample->sp = reinterpret_cast<Address>(context.Rsp);
+ sample->fp = reinterpret_cast<Address>(context.Rbp);
+#else
+ sample->pc = reinterpret_cast<Address>(context.Eip);
+ sample->sp = reinterpret_cast<Address>(context.Esp);
+ sample->fp = reinterpret_cast<Address>(context.Ebp);
+#endif
+#endif // USE_SIMULATOR
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+ }
+ ResumeThread(profiled_thread);
+ }
+
+#endif // USE_SIGNALS
+
+
+ // Protects the process wide state below.
+ static Mutex* mutex_;
+ static SamplerThread* instance_;
+
+ const int interval_;
+ List<Sampler*> active_samplers_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplerThread);
+};
+
+
+Mutex* SamplerThread::mutex_ = NULL;
+SamplerThread* SamplerThread::instance_ = NULL;
+
+
+//
+// StackTracer implementation
+//
+DISABLE_ASAN void TickSample::Trace(Isolate* isolate) {
+ ASSERT(isolate->IsInitialized());
+
+ // Avoid collecting traces while doing GC.
+ if (state == GC) return;
+
+ const Address js_entry_sp =
+ Isolate::js_entry_sp(isolate->thread_local_top());
+ if (js_entry_sp == 0) {
+ // Not executing JS now.
+ return;
+ }
+
+ external_callback = isolate->external_callback();
+
+ SafeStackTraceFrameIterator it(isolate, fp, sp, sp, js_entry_sp);
+ int i = 0;
+ while (!it.done() && i < TickSample::kMaxFramesCount) {
+ stack[i++] = it.frame()->pc();
+ it.Advance();
+ }
+ frames_count = i;
+}
+
+
+void Sampler::SetUp() {
+ SamplerThread::SetUp();
+}
+
+
+void Sampler::TearDown() {
+ SamplerThread::TearDown();
+}
+
+
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
+ profiling_(false),
+ active_(false),
+ samples_taken_(0) {
+ data_ = new PlatformData;
+}
+
+
+Sampler::~Sampler() {
+ ASSERT(!IsActive());
+ delete data_;
+}
+
+void Sampler::Start() {
+ ASSERT(!IsActive());
+ SetActive(true);
+ SamplerThread::AddActiveSampler(this);
+}
+
+
+void Sampler::Stop() {
+ ASSERT(IsActive());
+ SamplerThread::RemoveActiveSampler(this);
+ SetActive(false);
+}
+
+void Sampler::SampleStack(TickSample* sample) {
+ sample->Trace(isolate_);
+ if (++samples_taken_ < 0) samples_taken_ = 0;
+}
+
+} } // namespace v8::internal
diff --git a/src/sampler.h b/src/sampler.h
new file mode 100644
index 0000000..a76d8b9
--- /dev/null
+++ b/src/sampler.h
@@ -0,0 +1,120 @@
+// Copyright 2013 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_SAMPLER_H_
+#define V8_SAMPLER_H_
+
+#include "atomicops.h"
+#include "v8globals.h"
+
+namespace v8 {
+namespace internal {
+
+class Isolate;
+
+// ----------------------------------------------------------------------------
+// Sampler
+//
+// A sampler periodically samples the state of the VM and optionally
+// (if used for profiling) the program counter and stack pointer for
+// the thread that created it.
+
+// TickSample captures the information collected for each sample.
+struct TickSample {
+ TickSample()
+ : state(OTHER),
+ pc(NULL),
+ sp(NULL),
+ fp(NULL),
+ external_callback(NULL),
+ frames_count(0) {}
+ void Trace(Isolate* isolate);
+ StateTag state; // The state of the VM.
+ Address pc; // Instruction pointer.
+ Address sp; // Stack pointer.
+ Address fp; // Frame pointer.
+ Address external_callback;
+ static const int kMaxFramesCount = 64;
+ Address stack[kMaxFramesCount]; // Call stack.
+ int frames_count : 8; // Number of captured frames.
+};
+
+class Sampler {
+ public:
+ // Initializes the Sampler support. Called once at VM startup.
+ static void SetUp();
+ static void TearDown();
+
+ // Initialize sampler.
+ Sampler(Isolate* isolate, int interval);
+ virtual ~Sampler();
+
+ Isolate* isolate() const { return isolate_; }
+ int interval() const { return interval_; }
+
+ // Performs stack sampling.
+ void SampleStack(TickSample* sample);
+
+ // This method is called for each sampling period with the current
+ // program counter.
+ virtual void Tick(TickSample* sample) = 0;
+
+ // Start and stop sampler.
+ void Start();
+ void Stop();
+
+ // Is the sampler used for profiling?
+ bool IsProfiling() const { return NoBarrier_Load(&profiling_) > 0; }
+ void IncreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, 1); }
+ void DecreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, -1); }
+
+ // Whether the sampler is running (that is, consumes resources).
+ bool IsActive() const { return NoBarrier_Load(&active_); }
+
+ // Used in tests to make sure that stack sampling is performed.
+ int samples_taken() const { return samples_taken_; }
+ void ResetSamplesTaken() { samples_taken_ = 0; }
+
+ class PlatformData;
+ PlatformData* platform_data() const { return data_; }
+
+ private:
+ void SetActive(bool value) { NoBarrier_Store(&active_, value); }
+
+ Isolate* isolate_;
+ const int interval_;
+ Atomic32 profiling_;
+ Atomic32 active_;
+ PlatformData* data_; // Platform specific data.
+ int samples_taken_; // Counts stack samples taken.
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_SAMPLER_H_
diff --git a/src/scanner.h b/src/scanner.h
index dd1bfb8..92418f7 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -42,26 +42,6 @@
namespace internal {
-// General collection of (multi-)bit-flags that can be passed to scanners and
-// parsers to signify their (initial) mode of operation.
-enum ParsingFlags {
- kNoParsingFlags = 0,
- // Embed LanguageMode values in parsing flags, i.e., equivalent to:
- // CLASSIC_MODE = 0,
- // STRICT_MODE,
- // EXTENDED_MODE,
- kLanguageModeMask = 0x03,
- kAllowLazy = 0x04,
- kAllowNativesSyntax = 0x08,
- kAllowModules = 0x10,
- kAllowGenerators = 0x20
-};
-
-STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE);
-STATIC_ASSERT((kLanguageModeMask & STRICT_MODE) == STRICT_MODE);
-STATIC_ASSERT((kLanguageModeMask & EXTENDED_MODE) == EXTENDED_MODE);
-
-
// Returns the value (0 .. 15) of a hexadecimal character c.
// If c is not a legal hexadecimal character, returns a value < 0.
inline int HexValue(uc32 c) {
@@ -235,7 +215,7 @@
void ExpandBuffer() {
Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
- memcpy(new_store.start(), backing_store_.start(), position_);
+ OS::MemCopy(new_store.start(), backing_store_.start(), position_);
backing_store_.Dispose();
backing_store_ = new_store;
}
diff --git a/src/scopes.cc b/src/scopes.cc
index 4ac9d0e..10548f9 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -197,6 +197,8 @@
outer_scope_calls_non_strict_eval_ = false;
inner_scope_calls_eval_ = false;
force_eager_compilation_ = false;
+ force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
+ ? outer_scope->has_forced_context_allocation() : false;
num_var_or_const_ = 0;
num_stack_slots_ = 0;
num_heap_slots_ = 0;
@@ -603,12 +605,18 @@
}
}
- // Collect temporaries which are always allocated on the stack.
+ // Collect temporaries which are always allocated on the stack, unless the
+ // context as a whole has forced context allocation.
for (int i = 0; i < temps_.length(); i++) {
Variable* var = temps_[i];
if (var->is_used()) {
- ASSERT(var->IsStackLocal());
- stack_locals->Add(var, zone());
+ if (var->IsContextSlot()) {
+ ASSERT(has_forced_context_allocation());
+ context_locals->Add(var, zone());
+ } else {
+ ASSERT(var->IsStackLocal());
+ stack_locals->Add(var, zone());
+ }
}
}
@@ -1182,8 +1190,11 @@
// an eval() call or a runtime with lookup), it must be allocated in the
// context.
//
- // Exceptions: temporary variables are never allocated in a context;
- // catch-bound variables are always allocated in a context.
+ // Exceptions: If the scope as a whole has forced context allocation, all
+ // variables will have context allocation, even temporaries. Otherwise
+ // temporary variables are always stack-allocated. Catch-bound variables are
+ // always context-allocated.
+ if (has_forced_context_allocation()) return true;
if (var->mode() == TEMPORARY) return false;
if (var->mode() == INTERNAL) return true;
if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
diff --git a/src/scopes.h b/src/scopes.h
index 3ca2dcf..66384a1 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -269,6 +269,15 @@
end_position_ = statement_pos;
}
+ // In some cases we want to force context allocation for a whole scope.
+ void ForceContextAllocation() {
+ ASSERT(!already_resolved());
+ force_context_allocation_ = true;
+ }
+ bool has_forced_context_allocation() const {
+ return force_context_allocation_;
+ }
+
// ---------------------------------------------------------------------------
// Predicates.
@@ -494,6 +503,7 @@
bool outer_scope_calls_non_strict_eval_;
bool inner_scope_calls_eval_;
bool force_eager_compilation_;
+ bool force_context_allocation_;
// True if it doesn't need scope resolution (e.g., if the scope was
// constructed based on a serialized scope info or a catch context).
diff --git a/src/serialize.h b/src/serialize.h
index e0bcf4e..dc9ffd6 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -311,7 +311,7 @@
void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
- memcpy(to, data_ + position_, number_of_bytes);
+ OS::MemCopy(to, data_ + position_, number_of_bytes);
position_ += number_of_bytes;
}
diff --git a/src/spaces.cc b/src/spaces.cc
index f8e6a1e..e413bf1 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -467,6 +467,11 @@
chunk->progress_bar_ = 0;
chunk->high_water_mark_ = static_cast<int>(area_start - base);
chunk->parallel_sweeping_ = 0;
+ chunk->available_in_small_free_list_ = 0;
+ chunk->available_in_medium_free_list_ = 0;
+ chunk->available_in_large_free_list_ = 0;
+ chunk->available_in_huge_free_list_ = 0;
+ chunk->non_available_small_blocks_ = 0;
chunk->ResetLiveBytes();
Bitmap::Clear(chunk);
chunk->initialize_scan_on_scavenge(false);
@@ -697,6 +702,15 @@
}
+void Page::ResetFreeListStatistics() {
+ non_available_small_blocks_ = 0;
+ available_in_small_free_list_ = 0;
+ available_in_medium_free_list_ = 0;
+ available_in_large_free_list_ = 0;
+ available_in_huge_free_list_ = 0;
+}
+
+
Page* MemoryAllocator::AllocatePage(intptr_t size,
PagedSpace* owner,
Executability executable) {
@@ -1057,6 +1071,23 @@
}
+void PagedSpace::ObtainFreeListStatistics(Page* page, SizeStats* sizes) {
+ sizes->huge_size_ = page->available_in_huge_free_list();
+ sizes->small_size_ = page->available_in_small_free_list();
+ sizes->medium_size_ = page->available_in_medium_free_list();
+ sizes->large_size_ = page->available_in_large_free_list();
+}
+
+
+void PagedSpace::ResetFreeListStatistics() {
+ PageIterator page_iterator(this);
+ while (page_iterator.has_next()) {
+ Page* page = page_iterator.next();
+ page->ResetFreeListStatistics();
+ }
+}
+
+
void PagedSpace::ReleasePage(Page* page, bool unlink) {
ASSERT(page->LiveBytes() == 0);
ASSERT(AreaSize() == page->area_size());
@@ -2056,20 +2087,6 @@
}
-intptr_t FreeListCategory::CountFreeListItemsInList(Page* p) {
- int sum = 0;
- FreeListNode* n = top_;
- while (n != NULL) {
- if (Page::FromAddress(n->address()) == p) {
- FreeSpace* free_space = reinterpret_cast<FreeSpace*>(n);
- sum += free_space->Size();
- }
- n = n->next();
- }
- return sum;
-}
-
-
intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) {
int sum = 0;
FreeListNode** n = &top_;
@@ -2170,20 +2187,28 @@
FreeListNode* node = FreeListNode::FromAddress(start);
node->set_size(heap_, size_in_bytes);
+ Page* page = Page::FromAddress(start);
// Early return to drop too-small blocks on the floor.
- if (size_in_bytes < kSmallListMin) return size_in_bytes;
+ if (size_in_bytes < kSmallListMin) {
+ page->add_non_available_small_blocks(size_in_bytes);
+ return size_in_bytes;
+ }
// Insert other blocks at the head of a free list of the appropriate
// magnitude.
if (size_in_bytes <= kSmallListMax) {
small_list_.Free(node, size_in_bytes);
+ page->add_available_in_small_free_list(size_in_bytes);
} else if (size_in_bytes <= kMediumListMax) {
medium_list_.Free(node, size_in_bytes);
+ page->add_available_in_medium_free_list(size_in_bytes);
} else if (size_in_bytes <= kLargeListMax) {
large_list_.Free(node, size_in_bytes);
+ page->add_available_in_large_free_list(size_in_bytes);
} else {
huge_list_.Free(node, size_in_bytes);
+ page->add_available_in_huge_free_list(size_in_bytes);
}
ASSERT(IsVeryLong() || available() == SumFreeLists());
@@ -2193,20 +2218,33 @@
FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
FreeListNode* node = NULL;
+ Page* page = NULL;
if (size_in_bytes <= kSmallAllocationMax) {
node = small_list_.PickNodeFromList(node_size);
- if (node != NULL) return node;
+ if (node != NULL) {
+ page = Page::FromAddress(node->address());
+ page->add_available_in_small_free_list(-(*node_size));
+ return node;
+ }
}
if (size_in_bytes <= kMediumAllocationMax) {
node = medium_list_.PickNodeFromList(node_size);
- if (node != NULL) return node;
+ if (node != NULL) {
+ page = Page::FromAddress(node->address());
+ page->add_available_in_medium_free_list(-(*node_size));
+ return node;
+ }
}
if (size_in_bytes <= kLargeAllocationMax) {
node = large_list_.PickNodeFromList(node_size);
- if (node != NULL) return node;
+ if (node != NULL) {
+ page = Page::FromAddress(node->address());
+ page->add_available_in_large_free_list(-(*node_size));
+ return node;
+ }
}
int huge_list_available = huge_list_.available();
@@ -2216,7 +2254,10 @@
FreeListNode* cur_node = *cur;
while (cur_node != NULL &&
Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) {
- huge_list_available -= reinterpret_cast<FreeSpace*>(cur_node)->Size();
+ int size = reinterpret_cast<FreeSpace*>(cur_node)->Size();
+ huge_list_available -= size;
+ page = Page::FromAddress(cur_node->address());
+ page->add_available_in_huge_free_list(-size);
cur_node = cur_node->next();
}
@@ -2235,6 +2276,8 @@
*cur = node->next();
*node_size = size;
huge_list_available -= size;
+ page = Page::FromAddress(node->address());
+ page->add_available_in_huge_free_list(-size);
break;
}
}
@@ -2322,27 +2365,17 @@
}
-void FreeList::CountFreeListItems(Page* p, SizeStats* sizes) {
- sizes->huge_size_ = huge_list_.CountFreeListItemsInList(p);
- if (sizes->huge_size_ < p->area_size()) {
- sizes->small_size_ = small_list_.CountFreeListItemsInList(p);
- sizes->medium_size_ = medium_list_.CountFreeListItemsInList(p);
- sizes->large_size_ = large_list_.CountFreeListItemsInList(p);
- } else {
- sizes->small_size_ = 0;
- sizes->medium_size_ = 0;
- sizes->large_size_ = 0;
- }
-}
-
-
intptr_t FreeList::EvictFreeListItems(Page* p) {
intptr_t sum = huge_list_.EvictFreeListItemsInList(p);
+ p->set_available_in_huge_free_list(0);
if (sum < p->area_size()) {
sum += small_list_.EvictFreeListItemsInList(p) +
medium_list_.EvictFreeListItemsInList(p) +
large_list_.EvictFreeListItemsInList(p);
+ p->set_available_in_small_free_list(0);
+ p->set_available_in_medium_free_list(0);
+ p->set_available_in_large_free_list(0);
}
return sum;
diff --git a/src/spaces.h b/src/spaces.h
index 65eefd0..e7e4d52 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -547,7 +547,8 @@
kSlotsBufferOffset + kPointerSize + kPointerSize;
static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize +
- kIntSize + kIntSize + kPointerSize;
+ kIntSize + kIntSize + kPointerSize +
+ 5 * kPointerSize;
static const int kBodyOffset =
CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
@@ -701,6 +702,13 @@
intptr_t parallel_sweeping_;
+ // PagedSpace free-list statistics.
+ intptr_t available_in_small_free_list_;
+ intptr_t available_in_medium_free_list_;
+ intptr_t available_in_large_free_list_;
+ intptr_t available_in_huge_free_list_;
+ intptr_t non_available_small_blocks_;
+
static MemoryChunk* Initialize(Heap* heap,
Address base,
size_t size,
@@ -797,6 +805,21 @@
void ClearSweptPrecisely() { ClearFlag(WAS_SWEPT_PRECISELY); }
void ClearSweptConservatively() { ClearFlag(WAS_SWEPT_CONSERVATIVELY); }
+ void ResetFreeListStatistics();
+
+#define FRAGMENTATION_STATS_ACCESSORS(type, name) \
+ type name() { return name##_; } \
+ void set_##name(type name) { name##_ = name; } \
+ void add_##name(type name) { name##_ += name; }
+
+ FRAGMENTATION_STATS_ACCESSORS(intptr_t, non_available_small_blocks)
+ FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_small_free_list)
+ FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_medium_free_list)
+ FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_large_free_list)
+ FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_huge_free_list)
+
+#undef FRAGMENTATION_STATS_ACCESSORS
+
#ifdef DEBUG
void Print();
#endif // DEBUG
@@ -1432,8 +1455,6 @@
FreeListNode* PickNodeFromList(int *node_size);
- intptr_t CountFreeListItemsInList(Page* p);
-
intptr_t EvictFreeListItemsInList(Page* p);
void RepairFreeList(Heap* heap);
@@ -1528,19 +1549,6 @@
// Used after booting the VM.
void RepairLists(Heap* heap);
- struct SizeStats {
- intptr_t Total() {
- return small_size_ + medium_size_ + large_size_ + huge_size_;
- }
-
- intptr_t small_size_;
- intptr_t medium_size_;
- intptr_t large_size_;
- intptr_t huge_size_;
- };
-
- void CountFreeListItems(Page* p, SizeStats* sizes);
-
intptr_t EvictFreeListItems(Page* p);
FreeListCategory* small_list() { return &small_list_; }
@@ -1625,6 +1633,20 @@
// Approximate amount of physical memory committed for this space.
size_t CommittedPhysicalMemory();
+ struct SizeStats {
+ intptr_t Total() {
+ return small_size_ + medium_size_ + large_size_ + huge_size_;
+ }
+
+ intptr_t small_size_;
+ intptr_t medium_size_;
+ intptr_t large_size_;
+ intptr_t huge_size_;
+ };
+
+ void ObtainFreeListStatistics(Page* p, SizeStats* sizes);
+ void ResetFreeListStatistics();
+
// Sets the capacity, the available space and the wasted space to zero.
// The stats are rebuilt during sweeping by adding each page to the
// capacity and the size when it is encountered. As free spaces are
@@ -1632,6 +1654,7 @@
// to the available and wasted totals.
void ClearStats() {
accounting_stats_.ClearSizeWaste();
+ ResetFreeListStatistics();
}
// Increases the number of available bytes of that space.
@@ -1785,10 +1808,6 @@
Page* FirstPage() { return anchor_.next_page(); }
Page* LastPage() { return anchor_.prev_page(); }
- void CountFreeListItems(Page* p, FreeList::SizeStats* sizes) {
- free_list_.CountFreeListItems(p, sizes);
- }
-
void EvictEvacuationCandidatesFromFreeLists();
bool CanExpand();
diff --git a/src/string-stream.cc b/src/string-stream.cc
index bcc30f9..61eec0d 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -254,7 +254,7 @@
SmartArrayPointer<const char> StringStream::ToCString() const {
char* str = NewArray<char>(length_ + 1);
- memcpy(str, buffer_, length_);
+ OS::MemCopy(str, buffer_, length_);
str[length_] = '\0';
return SmartArrayPointer<const char>(str);
}
@@ -575,7 +575,7 @@
if (new_space == NULL) {
return space_;
}
- memcpy(new_space, space_, *bytes);
+ OS::MemCopy(new_space, space_, *bytes);
*bytes = new_bytes;
DeleteArray(space_);
space_ = new_space;
diff --git a/src/string.js b/src/string.js
index 2f8043c..4cae85b 100644
--- a/src/string.js
+++ b/src/string.js
@@ -25,24 +25,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
// This file relies on the fact that the following declaration has been made
// in runtime.js:
// var $String = global.String;
// var $NaN = 0/0;
+// -------------------------------------------------------------------
-// Set the String function and constructor.
-%SetCode($String, function(x) {
+function StringConstructor(x) {
var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
if (%_IsConstructCall()) {
%_SetValueOf(this, value);
} else {
return value;
}
-});
+}
-%FunctionSetPrototype($String, new $String());
// ECMA-262 section 15.5.4.2
function StringToString() {
@@ -994,16 +992,19 @@
function SetUpString() {
%CheckIsBootstrapping();
+
+ // Set the String function and constructor.
+ %SetCode($String, StringConstructor);
+ %FunctionSetPrototype($String, new $String());
+
// Set up the constructor property on the String prototype object.
%SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
-
// Set up the non-enumerable functions on the String object.
InstallFunctions($String, DONT_ENUM, $Array(
"fromCharCode", StringFromCharCode
));
-
// Set up the non-enumerable functions on the String prototype object.
InstallFunctions($String.prototype, DONT_ENUM, $Array(
"valueOf", StringValueOf,
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 553c6f5..396e92c 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -402,18 +402,30 @@
Handle<Code> StubCache::ComputeStoreField(Handle<Name> name,
Handle<JSObject> receiver,
LookupResult* lookup,
- Handle<Map> transition,
StrictModeFlag strict_mode) {
- Code::StubType type =
- transition.is_null() ? Code::FIELD : Code::MAP_TRANSITION;
-
Handle<Code> stub = FindIC(
- name, receiver, Code::STORE_IC, type, strict_mode);
+ name, receiver, Code::STORE_IC, Code::FIELD, strict_mode);
+ if (!stub.is_null()) return stub;
+
+ StoreStubCompiler compiler(isolate_, strict_mode);
+ Handle<Code> code = compiler.CompileStoreField(receiver, lookup, name);
+ JSObject::UpdateMapCodeCache(receiver, name, code);
+ return code;
+}
+
+
+Handle<Code> StubCache::ComputeStoreTransition(Handle<Name> name,
+ Handle<JSObject> receiver,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ StrictModeFlag strict_mode) {
+ Handle<Code> stub = FindIC(
+ name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode);
if (!stub.is_null()) return stub;
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
- compiler.CompileStoreField(receiver, lookup, transition, name);
+ compiler.CompileStoreTransition(receiver, lookup, transition, name);
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -534,20 +546,35 @@
return code;
}
+
Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name,
Handle<JSObject> receiver,
LookupResult* lookup,
- Handle<Map> transition,
StrictModeFlag strict_mode) {
- Code::StubType type =
- (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION;
Handle<Code> stub = FindIC(
- name, receiver, Code::KEYED_STORE_IC, type, strict_mode);
+ name, receiver, Code::KEYED_STORE_IC, Code::FIELD, strict_mode);
+ if (!stub.is_null()) return stub;
+
+ KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
+ Handle<Code> code = compiler.CompileStoreField(receiver, lookup, name);
+ JSObject::UpdateMapCodeCache(receiver, name, code);
+ return code;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedStoreTransition(
+ Handle<Name> name,
+ Handle<JSObject> receiver,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ StrictModeFlag strict_mode) {
+ Handle<Code> stub = FindIC(
+ name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode);
if (!stub.is_null()) return stub;
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
Handle<Code> code =
- compiler.CompileStoreField(receiver, lookup, transition, name);
+ compiler.CompileStoreTransition(receiver, lookup, transition, name);
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -1587,23 +1614,24 @@
}
-Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name) {
+Handle<Code> BaseStoreStubCompiler::CompileStoreTransition(
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name) {
Label miss, miss_restore_name;
GenerateNameCheck(name, this->name(), &miss);
- // Generate store field code.
- GenerateStoreField(masm(),
- object,
- lookup,
- transition,
- name,
- receiver(), this->name(), value(), scratch1(), scratch2(),
- &miss,
- &miss_restore_name);
+ GenerateStoreTransition(masm(),
+ object,
+ lookup,
+ transition,
+ name,
+ receiver(), this->name(), value(),
+ scratch1(), scratch2(),
+ &miss,
+ &miss_restore_name);
// Handle store cache miss.
GenerateRestoreName(masm(), &miss_restore_name, name);
@@ -1611,9 +1639,30 @@
TailCallBuiltin(masm(), MissBuiltin(kind()));
// Return the generated code.
- return GetICCode(kind(),
- transition.is_null() ? Code::FIELD : Code::MAP_TRANSITION,
- name);
+ return GetICCode(kind(), Code::MAP_TRANSITION, name);
+}
+
+
+Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Name> name) {
+ Label miss;
+
+ GenerateNameCheck(name, this->name(), &miss);
+
+ // Generate store field code.
+ GenerateStoreField(masm(),
+ object,
+ lookup,
+ receiver(), this->name(), value(), scratch1(), scratch2(),
+ &miss);
+
+ // Handle store cache miss.
+ __ bind(&miss);
+ TailCallBuiltin(masm(), MissBuiltin(kind()));
+
+ // Return the generated code.
+ return GetICCode(kind(), Code::FIELD, name);
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index bca3b7b..02bb541 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -162,9 +162,14 @@
Handle<Code> ComputeStoreField(Handle<Name> name,
Handle<JSObject> object,
LookupResult* lookup,
- Handle<Map> transition,
StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreTransition(Handle<Name> name,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ StrictModeFlag strict_mode);
+
Handle<Code> ComputeStoreNormal(StrictModeFlag strict_mode);
Handle<Code> ComputeStoreGlobal(Handle<Name> name,
@@ -193,8 +198,12 @@
Handle<Code> ComputeKeyedStoreField(Handle<Name> name,
Handle<JSObject> object,
LookupResult* lookup,
- Handle<Map> transition,
StrictModeFlag strict_mode);
+ Handle<Code> ComputeKeyedStoreTransition(Handle<Name> name,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ StrictModeFlag strict_mode);
Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
@@ -509,18 +518,28 @@
Register scratch2,
Label* miss_label);
+ void GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label,
+ Label* miss_restore_name);
+
void GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object,
LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
Register receiver_reg,
Register name_reg,
Register value_reg,
Register scratch1,
Register scratch2,
- Label* miss_label,
- Label* miss_restore_name);
+ Label* miss_label);
static Builtins::Name MissBuiltin(Code::Kind kind) {
switch (kind) {
@@ -781,9 +800,13 @@
virtual ~BaseStoreStubCompiler() { }
+ Handle<Code> CompileStoreTransition(Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name);
+
Handle<Code> CompileStoreField(Handle<JSObject> object,
LookupResult* lookup,
- Handle<Map> transition,
Handle<Name> name);
protected:
diff --git a/src/symbol.js b/src/symbol.js
index fb7476f..050e7d9 100644
--- a/src/symbol.js
+++ b/src/symbol.js
@@ -27,8 +27,14 @@
"use strict";
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
var $Symbol = global.Symbol;
+// -------------------------------------------------------------------
+
function SymbolConstructor(x) {
var value =
IS_SYMBOL(x) ? x : %CreateSymbol(IS_UNDEFINED(x) ? x : ToString(x));
diff --git a/src/third_party/vtune/ittnotify_config.h b/src/third_party/vtune/ittnotify_config.h
new file mode 100644
index 0000000..412e344
--- /dev/null
+++ b/src/third_party/vtune/ittnotify_config.h
@@ -0,0 +1,484 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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 _ITTNOTIFY_CONFIG_H_
+#define _ITTNOTIFY_CONFIG_H_
+
+/** @cond exclude_from_documentation */
+#ifndef ITT_OS_WIN
+# define ITT_OS_WIN 1
+#endif /* ITT_OS_WIN */
+
+#ifndef ITT_OS_LINUX
+# define ITT_OS_LINUX 2
+#endif /* ITT_OS_LINUX */
+
+#ifndef ITT_OS_MAC
+# define ITT_OS_MAC 3
+#endif /* ITT_OS_MAC */
+
+#ifndef ITT_OS
+# if defined WIN32 || defined _WIN32
+# define ITT_OS ITT_OS_WIN
+# elif defined( __APPLE__ ) && defined( __MACH__ )
+# define ITT_OS ITT_OS_MAC
+# else
+# define ITT_OS ITT_OS_LINUX
+# endif
+#endif /* ITT_OS */
+
+#ifndef ITT_PLATFORM_WIN
+# define ITT_PLATFORM_WIN 1
+#endif /* ITT_PLATFORM_WIN */
+
+#ifndef ITT_PLATFORM_POSIX
+# define ITT_PLATFORM_POSIX 2
+#endif /* ITT_PLATFORM_POSIX */
+
+#ifndef ITT_PLATFORM
+# if ITT_OS==ITT_OS_WIN
+# define ITT_PLATFORM ITT_PLATFORM_WIN
+# else
+# define ITT_PLATFORM ITT_PLATFORM_POSIX
+# endif /* _WIN32 */
+#endif /* ITT_PLATFORM */
+
+#if defined(_UNICODE) && !defined(UNICODE)
+#define UNICODE
+#endif
+
+#include <stddef.h>
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <tchar.h>
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <stdint.h>
+#if defined(UNICODE) || defined(_UNICODE)
+#include <wchar.h>
+#endif /* UNICODE || _UNICODE */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#ifndef CDECL
+# if ITT_PLATFORM==ITT_PLATFORM_WIN
+# define CDECL __cdecl
+# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+# if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+# define CDECL /* not actual on x86_64 platform */
+# else /* _M_X64 || _M_AMD64 || __x86_64__ */
+# define CDECL __attribute__ ((cdecl))
+# endif /* _M_X64 || _M_AMD64 || __x86_64__ */
+# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#endif /* CDECL */
+
+#ifndef STDCALL
+# if ITT_PLATFORM==ITT_PLATFORM_WIN
+# define STDCALL __stdcall
+# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+# if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+# define STDCALL /* not supported on x86_64 platform */
+# else /* _M_X64 || _M_AMD64 || __x86_64__ */
+# define STDCALL __attribute__ ((stdcall))
+# endif /* _M_X64 || _M_AMD64 || __x86_64__ */
+# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#endif /* STDCALL */
+
+#define ITTAPI CDECL
+#define LIBITTAPI CDECL
+
+/* TODO: Temporary for compatibility! */
+#define ITTAPI_CALL CDECL
+#define LIBITTAPI_CALL CDECL
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+/* use __forceinline (VC++ specific) */
+#define ITT_INLINE __forceinline
+#define ITT_INLINE_ATTRIBUTE /* nothing */
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+/*
+ * Generally, functions are not inlined unless optimization is specified.
+ * For functions declared inline, this attribute inlines the function even
+ * if no optimization level was specified.
+ */
+#ifdef __STRICT_ANSI__
+#define ITT_INLINE static
+#else /* __STRICT_ANSI__ */
+#define ITT_INLINE static inline
+#endif /* __STRICT_ANSI__ */
+#define ITT_INLINE_ATTRIBUTE __attribute__ ((always_inline))
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+/** @endcond */
+
+#ifndef ITT_ARCH_IA32
+# define ITT_ARCH_IA32 1
+#endif /* ITT_ARCH_IA32 */
+
+#ifndef ITT_ARCH_IA32E
+# define ITT_ARCH_IA32E 2
+#endif /* ITT_ARCH_IA32E */
+
+#ifndef ITT_ARCH_IA64
+# define ITT_ARCH_IA64 3
+#endif /* ITT_ARCH_IA64 */
+
+#ifndef ITT_ARCH
+# if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+# define ITT_ARCH ITT_ARCH_IA32E
+# elif defined _M_IA64 || defined __ia64
+# define ITT_ARCH ITT_ARCH_IA64
+# else
+# define ITT_ARCH ITT_ARCH_IA32
+# endif
+#endif
+
+#ifdef __cplusplus
+# define ITT_EXTERN_C extern "C"
+#else
+# define ITT_EXTERN_C /* nothing */
+#endif /* __cplusplus */
+
+#define ITT_TO_STR_AUX(x) #x
+#define ITT_TO_STR(x) ITT_TO_STR_AUX(x)
+
+#define __ITT_BUILD_ASSERT(expr, suffix) do { static char __itt_build_check_##suffix[(expr) ? 1 : -1]; __itt_build_check_##suffix[0] = 0; } while(0)
+#define _ITT_BUILD_ASSERT(expr, suffix) __ITT_BUILD_ASSERT((expr), suffix)
+#define ITT_BUILD_ASSERT(expr) _ITT_BUILD_ASSERT((expr), __LINE__)
+
+#define ITT_MAGIC { 0xED, 0xAB, 0xAB, 0xEC, 0x0D, 0xEE, 0xDA, 0x30 }
+
+/* Replace with snapshot date YYYYMMDD for promotion build. */
+#define API_VERSION_BUILD 20111111
+
+#ifndef API_VERSION_NUM
+#define API_VERSION_NUM 0.0.0
+#endif /* API_VERSION_NUM */
+
+#define API_VERSION "ITT-API-Version " ITT_TO_STR(API_VERSION_NUM) " (" ITT_TO_STR(API_VERSION_BUILD) ")"
+
+/* OS communication functions */
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <windows.h>
+typedef HMODULE lib_t;
+typedef DWORD TIDT;
+typedef CRITICAL_SECTION mutex_t;
+#define MUTEX_INITIALIZER { 0 }
+#define strong_alias(name, aliasname) /* empty for Windows */
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <dlfcn.h>
+#if defined(UNICODE) || defined(_UNICODE)
+#include <wchar.h>
+#endif /* UNICODE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1 /* need for PTHREAD_MUTEX_RECURSIVE */
+#endif /* _GNU_SOURCE */
+#include <pthread.h>
+typedef void* lib_t;
+typedef pthread_t TIDT;
+typedef pthread_mutex_t mutex_t;
+#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define _strong_alias(name, aliasname) extern __typeof (name) aliasname __attribute__ ((alias (#name)));
+#define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#define __itt_get_proc(lib, name) GetProcAddress(lib, name)
+#define __itt_mutex_init(mutex) InitializeCriticalSection(mutex)
+#define __itt_mutex_lock(mutex) EnterCriticalSection(mutex)
+#define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex)
+#define __itt_load_lib(name) LoadLibraryA(name)
+#define __itt_unload_lib(handle) FreeLibrary(handle)
+#define __itt_system_error() (int)GetLastError()
+#define __itt_fstrcmp(s1, s2) lstrcmpA(s1, s2)
+#define __itt_fstrlen(s) lstrlenA(s)
+#define __itt_fstrcpyn(s1, s2, l) lstrcpynA(s1, s2, l)
+#define __itt_fstrdup(s) _strdup(s)
+#define __itt_thread_id() GetCurrentThreadId()
+#define __itt_thread_yield() SwitchToThread()
+#ifndef ITT_SIMPLE_INIT
+ITT_INLINE int __itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE int __itt_interlocked_increment(volatile long* ptr)
+{
+ return InterlockedIncrement(ptr);
+}
+#endif /* ITT_SIMPLE_INIT */
+#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
+#define __itt_get_proc(lib, name) dlsym(lib, name)
+#define __itt_mutex_init(mutex) \
+ { \
+ pthread_mutexattr_t mutex_attr; \
+ int error_code = pthread_mutexattr_init(&mutex_attr); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutexattr_init", error_code); \
+ error_code = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutexattr_settype", error_code); \
+ error_code = pthread_mutex_init(mutex, &mutex_attr); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutex_init", error_code); \
+ error_code = pthread_mutexattr_destroy(&mutex_attr); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutexattr_destroy", error_code); \
+ }
+#define __itt_mutex_lock(mutex) pthread_mutex_lock(mutex)
+#define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
+#define __itt_load_lib(name) dlopen(name, RTLD_LAZY)
+#define __itt_unload_lib(handle) dlclose(handle)
+#define __itt_system_error() errno
+#define __itt_fstrcmp(s1, s2) strcmp(s1, s2)
+#define __itt_fstrlen(s) strlen(s)
+#define __itt_fstrcpyn(s1, s2, l) strncpy(s1, s2, l)
+#define __itt_fstrdup(s) strdup(s)
+#define __itt_thread_id() pthread_self()
+#define __itt_thread_yield() sched_yield()
+#if ITT_ARCH==ITT_ARCH_IA64
+#ifdef __INTEL_COMPILER
+#define __TBB_machine_fetchadd4(addr, val) __fetchadd4_acq((void *)addr, val)
+#else /* __INTEL_COMPILER */
+/* TODO: Add Support for not Intel compilers for IA64 */
+#endif /* __INTEL_COMPILER */
+#else /* ITT_ARCH!=ITT_ARCH_IA64 */
+/*ITT_INLINE int __TBB_machine_fetchadd4(volatile void* ptr, long addend) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE int __TBB_machine_fetchadd4(volatile void* ptr, long addend)
+{
+ int result;
+ __asm__ __volatile__("lock\nxaddl %0,%1"
+ : "=r"(result),"=m"(*(long*)ptr)
+ : "0"(addend), "m"(*(long*)ptr)
+ : "memory");
+ return result;
+}
+*/
+#endif /* ITT_ARCH==ITT_ARCH_IA64 */
+#ifndef ITT_SIMPLE_INIT
+/*ITT_INLINE int __itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE int __itt_interlocked_increment(volatile long* ptr)
+{
+ return __TBB_machine_fetchadd4(ptr, 1) + 1;
+}
+*/
+#endif /* ITT_SIMPLE_INIT */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+typedef enum {
+ __itt_collection_normal = 0,
+ __itt_collection_paused = 1
+} __itt_collection_state;
+
+typedef enum {
+ __itt_thread_normal = 0,
+ __itt_thread_ignored = 1
+} __itt_thread_state;
+
+#pragma pack(push, 8)
+
+typedef struct ___itt_thread_info
+{
+ const char* nameA; /*!< Copy of original name in ASCII. */
+#if defined(UNICODE) || defined(_UNICODE)
+ const wchar_t* nameW; /*!< Copy of original name in UNICODE. */
+#else /* UNICODE || _UNICODE */
+ void* nameW;
+#endif /* UNICODE || _UNICODE */
+ TIDT tid;
+ __itt_thread_state state; /*!< Thread state (paused or normal) */
+ int extra1; /*!< Reserved to the runtime */
+ void* extra2; /*!< Reserved to the runtime */
+ struct ___itt_thread_info* next;
+} __itt_thread_info;
+
+#include "ittnotify_types.h" /* For __itt_group_id definition */
+
+typedef struct ___itt_api_info_20101001
+{
+ const char* name;
+ void** func_ptr;
+ void* init_func;
+ __itt_group_id group;
+} __itt_api_info_20101001;
+
+typedef struct ___itt_api_info
+{
+ const char* name;
+ void** func_ptr;
+ void* init_func;
+ void* null_func;
+ __itt_group_id group;
+} __itt_api_info;
+
+struct ___itt_domain;
+struct ___itt_string_handle;
+
+typedef struct ___itt_global
+{
+ unsigned char magic[8];
+ unsigned long version_major;
+ unsigned long version_minor;
+ unsigned long version_build;
+ volatile long api_initialized;
+ volatile long mutex_initialized;
+ volatile long atomic_counter;
+ mutex_t mutex;
+ lib_t lib;
+ void* error_handler;
+ const char** dll_path_ptr;
+ __itt_api_info* api_list_ptr;
+ struct ___itt_global* next;
+ /* Joinable structures below */
+ __itt_thread_info* thread_list;
+ struct ___itt_domain* domain_list;
+ struct ___itt_string_handle* string_list;
+ __itt_collection_state state;
+} __itt_global;
+
+#pragma pack(pop)
+
+#define NEW_THREAD_INFO_W(gptr,h,h_tail,t,s,n) { \
+ h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
+ if (h != NULL) { \
+ h->tid = t; \
+ h->nameA = NULL; \
+ h->nameW = n ? _wcsdup(n) : NULL; \
+ h->state = s; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->thread_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_THREAD_INFO_A(gptr,h,h_tail,t,s,n) { \
+ h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
+ if (h != NULL) { \
+ h->tid = t; \
+ h->nameA = n ? __itt_fstrdup(n) : NULL; \
+ h->nameW = NULL; \
+ h->state = s; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->thread_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_DOMAIN_W(gptr,h,h_tail,name) { \
+ h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
+ if (h != NULL) { \
+ h->flags = 0; /* domain is disabled by default */ \
+ h->nameA = NULL; \
+ h->nameW = name ? _wcsdup(name) : NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->domain_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_DOMAIN_A(gptr,h,h_tail,name) { \
+ h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
+ if (h != NULL) { \
+ h->flags = 0; /* domain is disabled by default */ \
+ h->nameA = name ? __itt_fstrdup(name) : NULL; \
+ h->nameW = NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->domain_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_STRING_HANDLE_W(gptr,h,h_tail,name) { \
+ h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
+ if (h != NULL) { \
+ h->strA = NULL; \
+ h->strW = name ? _wcsdup(name) : NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->string_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_STRING_HANDLE_A(gptr,h,h_tail,name) { \
+ h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
+ if (h != NULL) { \
+ h->strA = name ? __itt_fstrdup(name) : NULL; \
+ h->strW = NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->string_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#endif /* _ITTNOTIFY_CONFIG_H_ */
+
diff --git a/src/third_party/vtune/ittnotify_types.h b/src/third_party/vtune/ittnotify_types.h
new file mode 100644
index 0000000..736c1f5
--- /dev/null
+++ b/src/third_party/vtune/ittnotify_types.h
@@ -0,0 +1,113 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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 _ITTNOTIFY_TYPES_H_
+#define _ITTNOTIFY_TYPES_H_
+
+typedef enum ___itt_group_id
+{
+ __itt_group_none = 0,
+ __itt_group_legacy = 1<<0,
+ __itt_group_control = 1<<1,
+ __itt_group_thread = 1<<2,
+ __itt_group_mark = 1<<3,
+ __itt_group_sync = 1<<4,
+ __itt_group_fsync = 1<<5,
+ __itt_group_jit = 1<<6,
+ __itt_group_model = 1<<7,
+ __itt_group_splitter_min = 1<<7,
+ __itt_group_counter = 1<<8,
+ __itt_group_frame = 1<<9,
+ __itt_group_stitch = 1<<10,
+ __itt_group_heap = 1<<11,
+ __itt_group_splitter_max = 1<<12,
+ __itt_group_structure = 1<<12,
+ __itt_group_suppress = 1<<13,
+ __itt_group_all = -1
+} __itt_group_id;
+
+#pragma pack(push, 8)
+
+typedef struct ___itt_group_list
+{
+ __itt_group_id id;
+ const char* name;
+} __itt_group_list;
+
+#pragma pack(pop)
+
+#define ITT_GROUP_LIST(varname) \
+ static __itt_group_list varname[] = { \
+ { __itt_group_all, "all" }, \
+ { __itt_group_control, "control" }, \
+ { __itt_group_thread, "thread" }, \
+ { __itt_group_mark, "mark" }, \
+ { __itt_group_sync, "sync" }, \
+ { __itt_group_fsync, "fsync" }, \
+ { __itt_group_jit, "jit" }, \
+ { __itt_group_model, "model" }, \
+ { __itt_group_counter, "counter" }, \
+ { __itt_group_frame, "frame" }, \
+ { __itt_group_stitch, "stitch" }, \
+ { __itt_group_heap, "heap" }, \
+ { __itt_group_structure, "structure" }, \
+ { __itt_group_suppress, "suppress" }, \
+ { __itt_group_none, NULL } \
+ }
+
+#endif /* _ITTNOTIFY_TYPES_H_ */
+
diff --git a/src/third_party/vtune/jitprofiling.cc b/src/third_party/vtune/jitprofiling.cc
new file mode 100644
index 0000000..b3952b3
--- /dev/null
+++ b/src/third_party/vtune/jitprofiling.cc
@@ -0,0 +1,499 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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 "ittnotify_config.h"
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <windows.h>
+#pragma optimize("", off)
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <pthread.h>
+#include <dlfcn.h>
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <malloc.h>
+#include <stdlib.h>
+
+#include "jitprofiling.h"
+
+static const char rcsid[] = "\n@(#) $Revision: 234474 $\n";
+
+#define DLL_ENVIRONMENT_VAR "VS_PROFILER"
+
+#ifndef NEW_DLL_ENVIRONMENT_VAR
+#if ITT_ARCH==ITT_ARCH_IA32
+#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
+#else
+#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
+#endif
+#endif /* NEW_DLL_ENVIRONMENT_VAR */
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#define DEFAULT_DLLNAME "JitPI.dll"
+HINSTANCE m_libHandle = NULL;
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#define DEFAULT_DLLNAME "libJitPI.so"
+void* m_libHandle = NULL;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+/* default location of JIT profiling agent on Android */
+#define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"
+
+/* the function pointers */
+typedef unsigned int(*TPInitialize)(void);
+static TPInitialize FUNC_Initialize=NULL;
+
+typedef unsigned int(*TPNotify)(unsigned int, void*);
+static TPNotify FUNC_NotifyEvent=NULL;
+
+static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
+
+/* end collector dll part. */
+
+/* loadiJIT_Funcs() : this function is called just in the beginning and is responsible
+** to load the functions from BistroJavaCollector.dll
+** result:
+** on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1.
+** on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0.
+*/
+static int loadiJIT_Funcs(void);
+
+/* global representing whether the BistroJavaCollector can't be loaded */
+static int iJIT_DLL_is_missing = 0;
+
+/* Virtual stack - the struct is used as a virtual stack for each thread.
+** Every thread initializes with a stack of size INIT_TOP_STACK.
+** Every method entry decreases from the current stack point,
+** and when a thread stack reaches its top of stack (return from the global function),
+** the top of stack and the current stack increase. Notice that when returning from a function
+** the stack pointer is the address of the function return.
+*/
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+static DWORD threadLocalStorageHandle = 0;
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#define INIT_TOP_Stack 10000
+
+typedef struct
+{
+ unsigned int TopStack;
+ unsigned int CurrentStack;
+} ThreadStack, *pThreadStack;
+
+/* end of virtual stack. */
+
+/*
+** The function for reporting virtual-machine related events to VTune.
+** Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill in the stack_id
+** field in the iJIT_Method_NIDS structure, as VTune fills it.
+**
+** The return value in iJVM_EVENT_TYPE_ENTER_NIDS && iJVM_EVENT_TYPE_LEAVE_NIDS events
+** will be 0 in case of failure.
+** in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event it will be -1 if EventSpecificData == 0
+** otherwise it will be 0.
+*/
+
+ITT_EXTERN_C int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
+{
+ int ReturnValue;
+
+ /*******************************************************************************
+ ** This section is for debugging outside of VTune.
+ ** It creates the environment variables that indicates call graph mode.
+ ** If running outside of VTune remove the remark.
+ **
+
+ static int firstTime = 1;
+ char DoCallGraph[12] = "DoCallGraph";
+ if (firstTime)
+ {
+ firstTime = 0;
+ SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
+ }
+
+ ** end of section.
+ *******************************************************************************/
+
+ /* initialization part - the functions have not been loaded yet. This part
+ ** will load the functions, and check if we are in Call Graph mode.
+ ** (for special treatment).
+ */
+ if (!FUNC_NotifyEvent)
+ {
+ if (iJIT_DLL_is_missing)
+ return 0;
+
+ // load the Function from the DLL
+ if (!loadiJIT_Funcs())
+ return 0;
+
+ /* Call Graph initialization. */
+ }
+
+ /* If the event is method entry/exit, check that in the current mode
+ ** VTune is allowed to receive it
+ */
+ if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
+ (executionMode != iJIT_CALLGRAPH_ON))
+ {
+ return 0;
+ }
+ /* This section is performed when method enter event occurs.
+ ** It updates the virtual stack, or creates it if this is the first
+ ** method entry in the thread. The stack pointer is decreased.
+ */
+ if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+ // check for use of reserved method IDs
+ if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
+ return 0;
+
+ if (!threadStack)
+ {
+ // initialize the stack.
+ threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1);
+ threadStack->TopStack = INIT_TOP_Stack;
+ threadStack->CurrentStack = INIT_TOP_Stack;
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ TlsSetValue(threadLocalStorageHandle,(void*)threadStack);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pthread_setspecific(threadLocalStorageHandle,(void*)threadStack);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ }
+
+ // decrease the stack.
+ ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (threadStack->CurrentStack)--;
+ }
+
+ /* This section is performed when method leave event occurs
+ ** It updates the virtual stack.
+ ** Increases the stack pointer.
+ ** If the stack pointer reached the top (left the global function)
+ ** increase the pointer and the top pointer.
+ */
+ if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+ // check for use of reserved method IDs
+ if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
+ return 0;
+
+ if (!threadStack)
+ {
+ /* Error: first report in this thread is method exit */
+ exit (1);
+ }
+
+ ((piJIT_Method_NIDS) EventSpecificData)->stack_id = ++(threadStack->CurrentStack) + 1;
+
+ if (((piJIT_Method_NIDS) EventSpecificData)->stack_id > threadStack->TopStack)
+ ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (unsigned int)-1;
+ }
+
+ if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
+ {
+ // check for use of reserved method IDs
+ if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
+ return 0;
+ }
+
+ ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);
+
+ return ReturnValue;
+}
+
+ITT_EXTERN_C void JITAPI iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx NewModeCallBackFuncEx) // The new mode call back routine
+{
+ // is it already missing... or the load of functions from the DLL failed
+ if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
+ {
+ NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS); // then do not bother with notifications
+ /* Error: could not load JIT functions. */
+ return;
+ }
+ // nothing to do with the callback
+}
+
+/*
+** This function allows the user to query in which mode, if at all, VTune is running
+*/
+ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
+{
+ if (!iJIT_DLL_is_missing)
+ {
+ loadiJIT_Funcs();
+ }
+
+ return executionMode;
+}
+#include <stdio.h>
+/* this function loads the collector dll (BistroJavaCollector) and the relevant functions.
+** on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1.
+** on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0.
+*/
+static int loadiJIT_Funcs()
+{
+ static int bDllWasLoaded = 0;
+ char *dllName = (char*)rcsid; // !!! Just to avoid unused code elimination !!!
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ DWORD dNameLength = 0;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+ if(bDllWasLoaded)
+ {// dll was already loaded, no need to do it for the second time
+ return 1;
+ }
+
+ // Assumes that the DLL will not be found
+ iJIT_DLL_is_missing = 1;
+ FUNC_NotifyEvent = NULL;
+
+ if (m_libHandle)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FreeLibrary(m_libHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ dlclose(m_libHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ m_libHandle = NULL;
+ }
+
+ // try to get the dll name from the environment
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
+ if (dNameLength)
+ {
+ DWORD envret = 0;
+ dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
+ envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, dllName, dNameLength);
+ if (envret)
+ {
+ // Try to load the dll from the PATH...
+ m_libHandle = LoadLibraryExA(dllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+ free(dllName);
+ } else {
+ // Try to use old VS_PROFILER variable
+ dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
+ if (dNameLength)
+ {
+ DWORD envret = 0;
+ dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
+ envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, dllName, dNameLength);
+ if (envret)
+ {
+ // Try to load the dll from the PATH...
+ m_libHandle = LoadLibraryA(dllName);
+ }
+ free(dllName);
+ }
+ }
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
+ if (!dllName) {
+ dllName = getenv(DLL_ENVIRONMENT_VAR);
+ }
+#ifdef ANDROID
+ if (!dllName)
+ dllName = ANDROID_JIT_AGENT_PATH;
+#endif
+ if (dllName)
+ {
+ // Try to load the dll from the PATH...
+ m_libHandle = dlopen(dllName, RTLD_LAZY);
+ }
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+ if (!m_libHandle)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ }
+
+ // if the dll wasn't loaded - exit.
+ if (!m_libHandle)
+ {
+ iJIT_DLL_is_missing = 1; // don't try to initialize JIT agent the second time
+ return 0;
+ }
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ FUNC_NotifyEvent = reinterpret_cast<TPNotify>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "NotifyEvent")));
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ if (!FUNC_NotifyEvent)
+ {
+ FUNC_Initialize = NULL;
+ return 0;
+ }
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ FUNC_Initialize = reinterpret_cast<TPInitialize>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "Initialize")));
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ if (!FUNC_Initialize)
+ {
+ FUNC_NotifyEvent = NULL;
+ return 0;
+ }
+
+ executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
+ if (executionMode != iJIT_SAMPLING_ON)
+ executionMode = iJIT_SAMPLING_ON;
+
+ bDllWasLoaded = 1;
+ iJIT_DLL_is_missing = 0; // DLL is ok.
+
+ /*
+ ** Call Graph mode: init the thread local storage
+ ** (need to store the virtual stack there).
+ */
+ if ( executionMode == iJIT_CALLGRAPH_ON )
+ {
+ // Allocate a thread local storage slot for the thread "stack"
+ if (!threadLocalStorageHandle)
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ threadLocalStorageHandle = TlsAlloc();
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pthread_key_create(&threadLocalStorageHandle, NULL);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ }
+
+ return 1;
+}
+
+/*
+** This function should be called by the user whenever a thread ends, to free the thread
+** "virtual stack" storage
+*/
+ITT_EXTERN_C void JITAPI FinalizeThread()
+{
+ if (threadLocalStorageHandle)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ if (threadStack)
+ {
+ free (threadStack);
+ threadStack = NULL;
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ TlsSetValue (threadLocalStorageHandle, threadStack);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pthread_setspecific(threadLocalStorageHandle, threadStack);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ }
+ }
+}
+
+/*
+** This function should be called by the user when the process ends, to free the local
+** storage index
+*/
+ITT_EXTERN_C void JITAPI FinalizeProcess()
+{
+ if (m_libHandle)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FreeLibrary(m_libHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ dlclose(m_libHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ m_libHandle = NULL;
+ }
+
+ if (threadLocalStorageHandle)
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ TlsFree (threadLocalStorageHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ pthread_key_delete(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+}
+
+/*
+** This function should be called by the user for any method once.
+** The function will return a unique method ID, the user should maintain the ID for each
+** method
+*/
+ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
+{
+ static unsigned int methodID = 0x100000;
+
+ if (methodID == 0)
+ return 0; // ERROR : this is not a valid value
+
+ return methodID++;
+}
+
diff --git a/src/third_party/vtune/jitprofiling.h b/src/third_party/vtune/jitprofiling.h
new file mode 100644
index 0000000..abd6d8c
--- /dev/null
+++ b/src/third_party/vtune/jitprofiling.h
@@ -0,0 +1,298 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright (c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright (c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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 __JITPROFILING_H__
+#define __JITPROFILING_H__
+
+/*
+ * Various constants used by functions
+ */
+
+/* event notification */
+typedef enum iJIT_jvm_event
+{
+
+ /* shutdown */
+
+ /*
+ * Program exiting EventSpecificData NA
+ */
+ iJVM_EVENT_TYPE_SHUTDOWN = 2,
+
+ /* JIT profiling */
+
+ /*
+ * issued after method code jitted into memory but before code is executed
+ * EventSpecificData is an iJIT_Method_Load
+ */
+ iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED=13,
+
+ /* issued before unload. Method code will no longer be executed, but code
+ * and info are still in memory. The VTune profiler may capture method
+ * code only at this point EventSpecificData is iJIT_Method_Id
+ */
+ iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
+
+ /* Method Profiling */
+
+ /* method name, Id and stack is supplied
+ * issued when a method is about to be entered EventSpecificData is
+ * iJIT_Method_NIDS
+ */
+ iJVM_EVENT_TYPE_ENTER_NIDS = 19,
+
+ /* method name, Id and stack is supplied
+ * issued when a method is about to be left EventSpecificData is
+ * iJIT_Method_NIDS
+ */
+ iJVM_EVENT_TYPE_LEAVE_NIDS
+} iJIT_JVM_EVENT;
+
+typedef enum _iJIT_ModeFlags
+{
+ /* No need to Notify VTune, since VTune is not running */
+ iJIT_NO_NOTIFICATIONS = 0x0000,
+
+ /* when turned on the jit must call
+ * iJIT_NotifyEvent
+ * (
+ * iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
+ * )
+ * for all the method already jitted
+ */
+ iJIT_BE_NOTIFY_ON_LOAD = 0x0001,
+
+ /* when turned on the jit must call
+ * iJIT_NotifyEvent
+ * (
+ * iJVM_EVENT_TYPE_METHOD_UNLOAD_FINISHED,
+ * ) for all the method that are unloaded
+ */
+ iJIT_BE_NOTIFY_ON_UNLOAD = 0x0002,
+
+ /* when turned on the jit must instrument all
+ * the currently jited code with calls on
+ * method entries
+ */
+ iJIT_BE_NOTIFY_ON_METHOD_ENTRY = 0x0004,
+
+ /* when turned on the jit must instrument all
+ * the currently jited code with calls
+ * on method exit
+ */
+ iJIT_BE_NOTIFY_ON_METHOD_EXIT = 0x0008
+
+} iJIT_ModeFlags;
+
+
+ /* Flags used by iJIT_IsProfilingActive() */
+typedef enum _iJIT_IsProfilingActiveFlags
+{
+ /* No profiler is running. Currently not used */
+ iJIT_NOTHING_RUNNING = 0x0000,
+
+ /* Sampling is running. This is the default value
+ * returned by iJIT_IsProfilingActive()
+ */
+ iJIT_SAMPLING_ON = 0x0001,
+
+ /* Call Graph is running */
+ iJIT_CALLGRAPH_ON = 0x0002
+
+} iJIT_IsProfilingActiveFlags;
+
+/* Enumerator for the environment of methods*/
+typedef enum _iJDEnvironmentType
+{
+ iJDE_JittingAPI = 2
+} iJDEnvironmentType;
+
+/**********************************
+ * Data structures for the events *
+ **********************************/
+
+/* structure for the events:
+ * iJVM_EVENT_TYPE_METHOD_UNLOAD_START
+ */
+
+typedef struct _iJIT_Method_Id
+{
+ /* Id of the method (same as the one passed in
+ * the iJIT_Method_Load struct
+ */
+ unsigned int method_id;
+
+} *piJIT_Method_Id, iJIT_Method_Id;
+
+
+/* structure for the events:
+ * iJVM_EVENT_TYPE_ENTER_NIDS,
+ * iJVM_EVENT_TYPE_LEAVE_NIDS,
+ * iJVM_EVENT_TYPE_EXCEPTION_OCCURRED_NIDS
+ */
+
+typedef struct _iJIT_Method_NIDS
+{
+ /* unique method ID */
+ unsigned int method_id;
+
+ /* NOTE: no need to fill this field, it's filled by VTune */
+ unsigned int stack_id;
+
+ /* method name (just the method, without the class) */
+ char* method_name;
+} *piJIT_Method_NIDS, iJIT_Method_NIDS;
+
+/* structures for the events:
+ * iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
+ */
+
+typedef struct _LineNumberInfo
+{
+ /* x86 Offset from the begining of the method*/
+ unsigned int Offset;
+
+ /* source line number from the begining of the source file */
+ unsigned int LineNumber;
+
+} *pLineNumberInfo, LineNumberInfo;
+
+typedef struct _iJIT_Method_Load
+{
+ /* unique method ID - can be any unique value, (except 0 - 999) */
+ unsigned int method_id;
+
+ /* method name (can be with or without the class and signature, in any case
+ * the class name will be added to it)
+ */
+ char* method_name;
+
+ /* virtual address of that method - This determines the method range for the
+ * iJVM_EVENT_TYPE_ENTER/LEAVE_METHOD_ADDR events
+ */
+ void* method_load_address;
+
+ /* Size in memory - Must be exact */
+ unsigned int method_size;
+
+ /* Line Table size in number of entries - Zero if none */
+ unsigned int line_number_size;
+
+ /* Pointer to the begining of the line numbers info array */
+ pLineNumberInfo line_number_table;
+
+ /* unique class ID */
+ unsigned int class_id;
+
+ /* class file name */
+ char* class_file_name;
+
+ /* source file name */
+ char* source_file_name;
+
+ /* bits supplied by the user for saving in the JIT file */
+ void* user_data;
+
+ /* the size of the user data buffer */
+ unsigned int user_data_size;
+
+ /* NOTE: no need to fill this field, it's filled by VTune */
+ iJDEnvironmentType env;
+
+} *piJIT_Method_Load, iJIT_Method_Load;
+
+/* API Functions */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CDECL
+# if defined WIN32 || defined _WIN32
+# define CDECL __cdecl
+# else /* defined WIN32 || defined _WIN32 */
+# if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+# define CDECL /* not actual on x86_64 platform */
+# else /* _M_X64 || _M_AMD64 || __x86_64__ */
+# define CDECL __attribute__ ((cdecl))
+# endif /* _M_X64 || _M_AMD64 || __x86_64__ */
+# endif /* defined WIN32 || defined _WIN32 */
+#endif /* CDECL */
+
+#define JITAPI CDECL
+
+/* called when the settings are changed with new settings */
+typedef void (*iJIT_ModeChangedEx)(void *UserData, iJIT_ModeFlags Flags);
+
+int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData);
+
+/* The new mode call back routine */
+void JITAPI iJIT_RegisterCallbackEx(void *userdata,
+ iJIT_ModeChangedEx NewModeCallBackFuncEx);
+
+iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void);
+
+void JITAPI FinalizeThread(void);
+
+void JITAPI FinalizeProcess(void);
+
+unsigned int JITAPI iJIT_GetNewMethodID(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JITPROFILING_H__ */
diff --git a/src/third_party/vtune/v8-vtune.h b/src/third_party/vtune/v8-vtune.h
new file mode 100644
index 0000000..36c11e6
--- /dev/null
+++ b/src/third_party/vtune/v8-vtune.h
@@ -0,0 +1,69 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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_VTUNE_H_
+#define V8_VTUNE_H_
+
+namespace vTune {
+
+void InitilizeVtuneForV8();
+
+} // namespace vTune
+
+
+#endif // V8_VTUNE_H_
+
diff --git a/src/third_party/vtune/v8vtune.gyp b/src/third_party/vtune/v8vtune.gyp
new file mode 100644
index 0000000..cabd37a
--- /dev/null
+++ b/src/third_party/vtune/v8vtune.gyp
@@ -0,0 +1,56 @@
+# Copyright 2012 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.
+
+{
+ 'includes': ['../../../build/common.gypi'],
+ 'targets': [
+ {
+ 'target_name': 'v8_vtune',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../../tools/gyp/v8.gyp:v8',
+ ],
+ 'sources': [
+ 'ittnotify_config.h',
+ 'ittnotify_types.h',
+ 'jitprofiling.cc',
+ 'jitprofiling.h',
+ 'v8-vtune.h',
+ 'vtune-jit.cc',
+ 'vtune-jit.h',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': ['ENABLE_VTUNE_JIT_INTERFACE',],
+ 'conditions': [
+ ['OS != "win"', {
+ 'libraries': ['-ldl',],
+ }],
+ ],
+ },
+ },
+ ],
+}
diff --git a/src/third_party/vtune/vtune-jit.cc b/src/third_party/vtune/vtune-jit.cc
new file mode 100644
index 0000000..6ff595f
--- /dev/null
+++ b/src/third_party/vtune/vtune-jit.cc
@@ -0,0 +1,279 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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 <string.h>
+
+#ifdef WIN32
+#include <hash_map>
+using namespace std;
+#else
+// To avoid GCC 4.4 compilation warning about hash_map being deprecated.
+#define OLD_DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#include <ext/hash_map>
+#define __DEPRECATED OLD_DEPRECATED
+using namespace __gnu_cxx;
+#endif
+
+#include <list>
+
+#include "v8-vtune.h"
+#include "vtune-jit.h"
+
+namespace vTune {
+namespace internal {
+
+
+// This class is used to record the JITted code position info for JIT
+// code profiling.
+class JITCodeLineInfo {
+ public:
+ JITCodeLineInfo() { }
+
+ void SetPosition(intptr_t pc, int pos) {
+ AddCodeLineInfo(LineNumInfo(pc, pos));
+ }
+
+ struct LineNumInfo {
+ LineNumInfo(intptr_t pc, int pos)
+ : pc_(pc), pos_(pos) { }
+
+ intptr_t pc_;
+ int pos_;
+ };
+
+ std::list<LineNumInfo>* GetLineNumInfo() {
+ return &line_num_info_;
+ }
+
+ private:
+ void AddCodeLineInfo(const LineNumInfo& line_info) {
+ line_num_info_.push_back(line_info);
+ }
+ std::list<LineNumInfo> line_num_info_;
+};
+
+struct SameCodeObjects {
+ bool operator () (void* key1, void* key2) const {
+ return key1 == key2;
+ }
+};
+
+struct HashForCodeObject {
+ uint32_t operator () (void* code) const {
+ static const uintptr_t kGoldenRatio = 2654435761u;
+ uintptr_t hash = reinterpret_cast<uintptr_t>(code);
+ return static_cast<uint32_t>(hash * kGoldenRatio);
+ }
+};
+
+#ifdef WIN32
+typedef hash_map<void*, void*> JitInfoMap;
+#else
+typedef hash_map<void*, void*, HashForCodeObject, SameCodeObjects> JitInfoMap;
+#endif
+
+static JitInfoMap* GetEntries() {
+ static JitInfoMap* entries;
+ if (entries == NULL) {
+ entries = new JitInfoMap();
+ }
+ return entries;
+}
+
+static bool IsLineInfoTagged(void* ptr) {
+ return 0 != (reinterpret_cast<intptr_t>(ptr));
+}
+
+static JITCodeLineInfo* UntagLineInfo(void* ptr) {
+ return reinterpret_cast<JITCodeLineInfo*>(
+ reinterpret_cast<intptr_t>(ptr));
+}
+
+// The parameter str is a mixed pattern which contains the
+// function name and some other info. It comes from all the
+// Logger::CodeCreateEvent(...) function. This funtion get the
+// pure function name from the input parameter.
+static char* GetFunctionNameFromMixedName(const char* str, int length) {
+ int index = 0;
+ int count = 0;
+ char* start_ptr = NULL;
+
+ while (str[index++] != ':' && (index < length)) {}
+
+ if (str[index] == '*' || str[index] == '~' ) index++;
+ if (index >= length) return NULL;
+
+ start_ptr = const_cast<char*>(str + index);
+
+ while (index < length && str[index++] != ' ') {
+ count++;
+ }
+
+ char* result = new char[count + 1];
+ memcpy(result, start_ptr, count);
+ result[count] = '\0';
+
+ return result;
+}
+
+// The JitCodeEventHandler for Vtune.
+void VTUNEJITInterface::event_handler(const v8::JitCodeEvent* event) {
+ if (VTUNERUNNING && event != NULL) {
+ switch (event->type) {
+ case v8::JitCodeEvent::CODE_ADDED: {
+ char* temp_file_name = NULL;
+ char* temp_method_name =
+ GetFunctionNameFromMixedName(event->name.str,
+ static_cast<int>(event->name.len));
+ iJIT_Method_Load jmethod;
+ memset(&jmethod, 0, sizeof jmethod);
+ jmethod.method_id = iJIT_GetNewMethodID();
+ jmethod.method_load_address = event->code_start;
+ jmethod.method_size = static_cast<unsigned int>(event->code_len);
+ jmethod.method_name = temp_method_name;
+
+ Handle<Script> script = event->script;
+
+ if (*script != NULL) {
+ // Get the source file name and set it to jmethod.source_file_name
+ if ((*script->GetScriptName())->IsString()) {
+ Handle<String> script_name =
+ Handle<String>(String::Cast(*script->GetScriptName()));
+ temp_file_name = new char[script_name->Length() + 1];
+ script_name->WriteAscii(temp_file_name);
+ jmethod.source_file_name = temp_file_name;
+ }
+
+ JitInfoMap::iterator entry =
+ GetEntries()->find(event->code_start);
+ if (entry != GetEntries()->end() && IsLineInfoTagged(entry->first)) {
+ JITCodeLineInfo* line_info = UntagLineInfo(entry->second);
+ // Get the line_num_info and set it to jmethod.line_number_table
+ std::list<JITCodeLineInfo::LineNumInfo>* vtunelineinfo =
+ line_info->GetLineNumInfo();
+
+ jmethod.line_number_size = (unsigned int)vtunelineinfo->size();
+ jmethod.line_number_table =
+ reinterpret_cast<LineNumberInfo*>(
+ malloc(sizeof(LineNumberInfo)*jmethod.line_number_size));
+
+ std::list<JITCodeLineInfo::LineNumInfo>::iterator Iter;
+ int index = 0;
+ for (Iter = vtunelineinfo->begin();
+ Iter != vtunelineinfo->end();
+ Iter++) {
+ jmethod.line_number_table[index].Offset =
+ static_cast<unsigned int>(Iter->pc_);
+ jmethod.line_number_table[index++].LineNumber =
+ script->GetLineNumber(Iter->pos_)+1;
+ }
+ GetEntries()->erase(event->code_start);
+ }
+ }
+
+ iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
+ reinterpret_cast<void*>(&jmethod));
+ if (temp_method_name)
+ delete []temp_method_name;
+ if (temp_file_name)
+ delete []temp_file_name;
+ break;
+ }
+ // TODO(chunyang.dai@intel.com): code_move will be supported.
+ case v8::JitCodeEvent::CODE_MOVED:
+ break;
+ // Currently the CODE_REMOVED event is not issued.
+ case v8::JitCodeEvent::CODE_REMOVED:
+ break;
+ case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
+ JITCodeLineInfo* line_info =
+ reinterpret_cast<JITCodeLineInfo*>(event->user_data);
+ if (line_info != NULL) {
+ line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset),
+ static_cast<int>(event->line_info.pos));
+ }
+ break;
+ }
+ case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
+ v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
+ temp_event->user_data = new JITCodeLineInfo();
+ break;
+ }
+ case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
+ GetEntries()->insert(std::pair <void*, void*>(event->code_start, event->user_data));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return;
+}
+
+} // namespace internal
+
+void InitilizeVtuneForV8() {
+ if (v8::V8::Initialize()) {
+ v8::V8::SetFlagsFromString("--nocompact_code_space",
+ (int)strlen("--nocompact_code_space"));
+ v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+ vTune::internal::VTUNEJITInterface::event_handler);
+ }
+}
+
+} // namespace vTune
diff --git a/src/third_party/vtune/vtune-jit.h b/src/third_party/vtune/vtune-jit.h
new file mode 100644
index 0000000..42b8c3d
--- /dev/null
+++ b/src/third_party/vtune/vtune-jit.h
@@ -0,0 +1,82 @@
+/*
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+ 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 Intel Corporation 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 VTUNE_VTUNE_JIT_H_
+#define VTUNE_VTUNE_JIT_H_
+
+#include "jitprofiling.h"
+#include "../../../include/v8.h"
+
+#define VTUNERUNNING (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON)
+
+namespace vTune {
+namespace internal {
+using namespace v8;
+class VTUNEJITInterface {
+ public:
+ static void event_handler(const v8::JitCodeEvent* event);
+
+ private:
+ //static Mutex* vtunemutex_;
+};
+
+
+} } // namespace vTune::internal
+
+
+#endif // VTUNE_VTUNE_JIT_H_
+
diff --git a/src/typedarray.js b/src/typedarray.js
index c3e3ebd..24fcf1e 100644
--- a/src/typedarray.js
+++ b/src/typedarray.js
@@ -27,8 +27,14 @@
"use strict";
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
var $ArrayBuffer = global.__ArrayBuffer;
+// -------------------------------------------------------------------
+
function ArrayBufferConstructor(byteLength) { // length = 1
if (%_IsConstructCall()) {
var l = TO_POSITIVE_INTEGER(byteLength);
@@ -76,15 +82,74 @@
return result;
}
+// --------------- Typed Arrays ---------------------
+
+function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
+ return function (buffer, byteOffset, length) {
+ if (%_IsConstructCall()) {
+ if (!IS_ARRAYBUFFER(buffer)) {
+ throw MakeTypeError("Type error!");
+ }
+ var offset = IS_UNDEFINED(byteOffset)
+ ? 0 : offset = TO_POSITIVE_INTEGER(byteOffset);
+
+ if (offset % elementSize !== 0) {
+ throw MakeRangeError("invalid_typed_array_alignment",
+ "start offset", name, elementSize);
+ }
+ var bufferByteLength = %ArrayBufferGetByteLength(buffer);
+ if (offset >= bufferByteLength) {
+ throw MakeRangeError("invalid_typed_array_offset");
+ }
+
+ var newByteLength;
+ var newLength;
+ if (IS_UNDEFINED(length)) {
+ if (bufferByteLength % elementSize !== 0) {
+ throw MakeRangeError("invalid_typed_array_alignment",
+ "byte length", name, elementSize);
+ }
+ newByteLength = bufferByteLength - offset;
+ newLength = newByteLength / elementSize;
+ } else {
+ var newLength = TO_POSITIVE_INTEGER(length);
+ newByteLength = newLength * elementSize;
+ }
+ if (newByteLength > bufferByteLength) {
+ throw MakeRangeError("invalid_typed_array_length");
+ }
+ %TypedArrayInitialize(this, arrayId, buffer, offset, newByteLength);
+ } else {
+ return new constructor(buffer, byteOffset, length);
+ }
+ }
+}
+
+function TypedArrayGetBuffer() {
+ return %TypedArrayGetBuffer(this);
+}
+
+function TypedArrayGetByteLength() {
+ return %TypedArrayGetByteLength(this);
+}
+
+function TypedArrayGetByteOffset() {
+ return %TypedArrayGetByteOffset(this);
+}
+
+function TypedArrayGetLength() {
+ return %TypedArrayGetLength(this);
+}
// -------------------------------------------------------------------
-(function () {
+function SetUpArrayBuffer() {
%CheckIsBootstrapping();
- // Set up the Uint16Array constructor function.
+ // Set up the ArrayBuffer constructor function.
%SetCode($ArrayBuffer, ArrayBufferConstructor);
+ %FunctionSetPrototype($ArrayBuffer, new $Object());
// Set up the constructor property on the ArrayBuffer prototype object.
%SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
@@ -94,5 +159,34 @@
InstallFunctions($ArrayBuffer.prototype, DONT_ENUM, $Array(
"slice", ArrayBufferSlice
));
+}
-})();
+SetUpArrayBuffer();
+
+function SetupTypedArray(arrayId, name, constructor, elementSize) {
+ var f = CreateTypedArrayConstructor(name, elementSize,
+ arrayId, constructor);
+ %SetCode(constructor, f);
+ %FunctionSetPrototype(constructor, new $Object());
+
+ %SetProperty(constructor.prototype,
+ "constructor", constructor, DONT_ENUM);
+ %SetProperty(constructor.prototype,
+ "BYTES_PER_ELEMENT", elementSize,
+ READ_ONLY | DONT_ENUM | DONT_DELETE);
+ InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
+ InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
+ InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
+ InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
+}
+
+// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
+SetupTypedArray(1, "Uint8Array", global.__Uint8Array, 1);
+SetupTypedArray(2, "Int8Array", global.__Int8Array, 1);
+SetupTypedArray(3, "Uint16Array", global.__Uint16Array, 2);
+SetupTypedArray(4, "Int16Array", global.__Int16Array, 2);
+SetupTypedArray(5, "Uint32Array", global.__Uint32Array, 4);
+SetupTypedArray(6, "Int32Array", global.__Int32Array, 4);
+SetupTypedArray(7, "Float32Array", global.__Float32Array, 4);
+SetupTypedArray(8, "Float64Array", global.__Float64Array, 8);
+
diff --git a/src/unicode-inl.h b/src/unicode-inl.h
index 02be457..f861f9f 100644
--- a/src/unicode-inl.h
+++ b/src/unicode-inl.h
@@ -30,6 +30,7 @@
#include "unicode.h"
#include "checks.h"
+#include "platform.h"
namespace unibrow {
@@ -202,7 +203,7 @@
unsigned buffer_length =
last_byte_of_buffer_unused_ ? kBufferSize - 1 : kBufferSize;
unsigned memcpy_length = length <= buffer_length ? length : buffer_length;
- memcpy(data, buffer_, memcpy_length*sizeof(uint16_t));
+ v8::internal::OS::MemCopy(data, buffer_, memcpy_length*sizeof(uint16_t));
if (length <= buffer_length) return length;
ASSERT(unbuffered_start_ != NULL);
// Copy the rest the slow way.
diff --git a/src/uri.js b/src/uri.js
index 1de22f8..4e3f084 100644
--- a/src/uri.js
+++ b/src/uri.js
@@ -25,11 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
+// -------------------------------------------------------------------
+
// This file contains support for URI manipulations written in
// JavaScript.
-// Expect $String = global.String;
-
// Lazily initialized.
var hexCharArray = 0;
var hexCharCodeArray = 0;
@@ -437,6 +441,7 @@
function SetUpUri() {
%CheckIsBootstrapping();
+
// Set up non-enumerable URI functions on the global object and set
// their names.
InstallFunctions(global, DONT_ENUM, $Array(
diff --git a/src/utils.cc b/src/utils.cc
index 7e8c088..8462615 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -28,6 +28,7 @@
#include <stdarg.h>
#include "../include/v8stdint.h"
#include "checks.h"
+#include "platform.h"
#include "utils.h"
namespace v8 {
@@ -46,9 +47,9 @@
void SimpleStringBuilder::AddSubstring(const char* s, int n) {
- ASSERT(!is_finalized() && position_ + n < buffer_.length());
+ ASSERT(!is_finalized() && position_ + n <= buffer_.length());
ASSERT(static_cast<size_t>(n) <= strlen(s));
- memcpy(&buffer_[position_], s, n * kCharSize);
+ OS::MemCopy(&buffer_[position_], s, n * kCharSize);
position_ += n;
}
@@ -79,7 +80,13 @@
char* SimpleStringBuilder::Finalize() {
- ASSERT(!is_finalized() && position_ < buffer_.length());
+ ASSERT(!is_finalized() && position_ <= buffer_.length());
+ // If there is no space for null termination, overwrite last character.
+ if (position_ == buffer_.length()) {
+ position_--;
+ // Print ellipsis.
+ for (int i = 3; i > 0 && position_ > i; --i) buffer_[position_ - i] = '.';
+ }
buffer_[position_] = '\0';
// Make sure nobody managed to add a 0-character to the
// buffer while building the string.
diff --git a/src/utils.h b/src/utils.h
index c391b9c..b84d592 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -32,9 +32,9 @@
#include <string.h>
#include <climits>
-#include "globals.h"
-#include "checks.h"
#include "allocation.h"
+#include "checks.h"
+#include "globals.h"
namespace v8 {
namespace internal {
@@ -494,6 +494,7 @@
// When copying, make underlying Vector to reference our buffer.
EmbeddedVector(const EmbeddedVector& rhs)
: Vector<T>(rhs) {
+ // TODO(jkummerow): Refactor #includes and use OS::MemCopy() instead.
memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
set_start(buffer_);
}
@@ -501,6 +502,7 @@
EmbeddedVector& operator=(const EmbeddedVector& rhs) {
if (this == &rhs) return *this;
Vector<T>::operator=(rhs);
+ // TODO(jkummerow): Refactor #includes and use OS::MemCopy() instead.
memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
this->set_start(buffer_);
return *this;
@@ -876,6 +878,7 @@
INLINE(static Dest cast(const Source& source)) {
Dest dest;
+ // TODO(jkummerow): Refactor #includes and use OS::MemCopy() instead.
memcpy(&dest, &source, sizeof(dest));
return dest;
}
@@ -1019,6 +1022,9 @@
void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
T ToIntegral() const { return bits_; }
bool operator==(const EnumSet& set) { return bits_ == set.bits_; }
+ EnumSet<E, T> operator|(const EnumSet& set) const {
+ return EnumSet<E, T>(bits_ | set.bits_);
+ }
private:
T Mask(E element) const {
diff --git a/src/v8.cc b/src/v8.cc
index 2e8cd50..274128e 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -37,10 +37,10 @@
#include "heap-profiler.h"
#include "hydrogen.h"
#include "lithium-allocator.h"
-#include "log.h"
#include "objects.h"
#include "once.h"
#include "platform.h"
+#include "sampler.h"
#include "runtime-profiler.h"
#include "serialize.h"
#include "store-buffer.h"
@@ -123,6 +123,7 @@
delete call_completed_callbacks_;
call_completed_callbacks_ = NULL;
+ Sampler::TearDown();
OS::TearDown();
}
@@ -270,16 +271,15 @@
}
if (FLAG_trace_hydrogen) FLAG_parallel_recompilation = false;
OS::SetUp();
+ Sampler::SetUp();
CPU::SetUp();
use_crankshaft_ = FLAG_crankshaft
&& !Serializer::enabled()
&& CPU::SupportsCrankshaft();
OS::PostSetUp();
- RuntimeProfiler::GlobalSetUp();
ElementsAccessor::InitializeOncePerProcess();
LOperand::SetUpCaches();
SetUpJSCallerSavedCodeData();
- SamplerRegistry::SetUp();
ExternalReference::SetUp();
}
diff --git a/src/v8conversions.h b/src/v8conversions.h
index 0147d8c..9d618af 100644
--- a/src/v8conversions.h
+++ b/src/v8conversions.h
@@ -55,6 +55,19 @@
// Converts a string into an integer.
double StringToInt(UnicodeCache* unicode_cache, String* str, int radix);
+// Converts a number into size_t.
+inline size_t NumberToSize(Isolate* isolate,
+ Object* number) {
+ NoHandleAllocation hc(isolate);
+ if (number->IsSmi()) {
+ return Smi::cast(number)->value();
+ } else {
+ ASSERT(number->IsHeapNumber());
+ double value = HeapNumber::cast(number)->value();
+ return static_cast<size_t>(value);
+ }
+}
+
} } // namespace v8::internal
#endif // V8_V8CONVERSIONS_H_
diff --git a/src/v8globals.h b/src/v8globals.h
index 4b4d312..82e30f5 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -163,7 +163,6 @@
class Deserializer;
class MessageLocation;
class ObjectGroup;
-class TickSample;
class VirtualMemory;
class Mutex;
@@ -433,11 +432,10 @@
CPUID = 10, // x86
VFP3 = 1, // ARM
ARMv7 = 2, // ARM
- VFP2 = 3, // ARM
- SUDIV = 4, // ARM
- UNALIGNED_ACCESSES = 5, // ARM
- MOVW_MOVT_IMMEDIATE_LOADS = 6, // ARM
- VFP32DREGS = 7, // ARM
+ SUDIV = 3, // ARM
+ UNALIGNED_ACCESSES = 4, // ARM
+ MOVW_MOVT_IMMEDIATE_LOADS = 5, // ARM
+ VFP32DREGS = 6, // ARM
SAHF = 0, // x86
FPU = 1}; // MIPS
@@ -496,8 +494,8 @@
INTERNAL, // like VAR, but not user-visible (may or may not
// be in a context)
- TEMPORARY, // temporary variables (not user-visible), never
- // in a context
+ TEMPORARY, // temporary variables (not user-visible), stack-allocated
+ // unless the scope as a whole has forced context allocation
DYNAMIC, // always require dynamic lookup (we don't know
// the declaration)
diff --git a/src/v8natives.js b/src/v8natives.js
index d9dc096..83b5618 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -26,7 +26,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file relies on the fact that the following declarations have been made
-//
// in runtime.js:
// var $Object = global.Object;
// var $Boolean = global.Boolean;
@@ -43,7 +42,6 @@
// ----------------------------------------------------------------------------
-
// Helper function used to install functions on objects.
function InstallFunctions(object, attributes, functions) {
if (functions.length >= 8) {
@@ -61,7 +59,7 @@
}
-// Helper function to install a getter only property.
+// Helper function to install a getter-only accessor property.
function InstallGetter(object, name, getter) {
%FunctionSetName(getter, name);
%FunctionRemovePrototype(getter);
@@ -70,6 +68,18 @@
}
+// Helper function to install a getter/setter accessor property.
+function InstallGetterSetter(object, name, getter, setter) {
+ %FunctionSetName(getter, name);
+ %FunctionSetName(setter, name);
+ %FunctionRemovePrototype(getter);
+ %FunctionRemovePrototype(setter);
+ %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
+ %SetNativeFlag(getter);
+ %SetNativeFlag(setter);
+}
+
+
// Prevents changes to the prototype of a built-in function.
// The "prototype" property of the function object is made non-configurable,
// and the prototype object is made non-extensible. The latter prevents
@@ -186,6 +196,7 @@
// Set up global object.
function SetUpGlobal() {
%CheckIsBootstrapping();
+
// ECMA 262 - 15.1.1.1.
%SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
@@ -208,27 +219,10 @@
SetUpGlobal();
-// ----------------------------------------------------------------------------
-// Boolean (first part of definition)
-
-
-%SetCode($Boolean, function(x) {
- if (%_IsConstructCall()) {
- %_SetValueOf(this, ToBoolean(x));
- } else {
- return ToBoolean(x);
- }
-});
-
-%FunctionSetPrototype($Boolean, new $Boolean(false));
-
-%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
// ----------------------------------------------------------------------------
// Object
-$Object.prototype.constructor = $Object;
-
// ECMA-262 - 15.2.4.2
function ObjectToString() {
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
@@ -395,7 +389,8 @@
}
// Must be an AccessorDescriptor then. We never return a generic descriptor.
return { get: desc.getGet(),
- set: desc.getSet(),
+ set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
+ : desc.getSet(),
enumerable: desc.isEnumerable(),
configurable: desc.isConfigurable() };
}
@@ -937,7 +932,7 @@
// Step 4 - Special handling for array index.
var index = ToUint32(p);
- if (index == ToNumber(p) && index != 4294967295) {
+ if (ToString(index) == p && index != 4294967295) {
var length = obj.length;
var length_desc = GetOwnProperty(obj, "length");
if ((index >= length && !length_desc.isWritable()) ||
@@ -1326,7 +1321,25 @@
}
-%SetCode($Object, function(x) {
+// Harmony __proto__ getter.
+function ObjectGetProto() {
+ return %GetPrototype(this);
+}
+
+
+// Harmony __proto__ setter.
+function ObjectSetProto(obj) {
+ return %SetPrototype(this, obj);
+}
+
+
+// Harmony __proto__ poison pill.
+function ObjectPoisonProto(obj) {
+ throw MakeTypeError("proto_poison_pill", []);
+}
+
+
+function ObjectConstructor(x) {
if (%_IsConstructCall()) {
if (x == null) return this;
return ToObject(x);
@@ -1334,16 +1347,23 @@
if (x == null) return { };
return ToObject(x);
}
-});
+}
-%SetExpectedNumberOfProperties($Object, 4);
// ----------------------------------------------------------------------------
// Object
function SetUpObject() {
%CheckIsBootstrapping();
- // Set Up non-enumerable functions on the Object.prototype object.
+
+ %SetCode($Object, ObjectConstructor);
+ %FunctionSetName(ObjectPoisonProto, "__proto__");
+ %FunctionRemovePrototype(ObjectPoisonProto);
+ %SetExpectedNumberOfProperties($Object, 4);
+
+ %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
+
+ // Set up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array(
"toString", ObjectToString,
"toLocaleString", ObjectToLocaleString,
@@ -1356,6 +1376,10 @@
"__defineSetter__", ObjectDefineSetter,
"__lookupSetter__", ObjectLookupSetter
));
+ InstallGetterSetter($Object.prototype, "__proto__",
+ ObjectGetProto, ObjectSetProto);
+
+ // Set up non-enumerable functions in the Object object.
InstallFunctions($Object, DONT_ENUM, $Array(
"keys", ObjectKeys,
"create", ObjectCreate,
@@ -1376,9 +1400,19 @@
SetUpObject();
+
// ----------------------------------------------------------------------------
// Boolean
+function BooleanConstructor(x) {
+ if (%_IsConstructCall()) {
+ %_SetValueOf(this, ToBoolean(x));
+ } else {
+ return ToBoolean(x);
+ }
+}
+
+
function BooleanToString() {
// NOTE: Both Boolean objects and values can enter here as
// 'this'. This is not as dictated by ECMA-262.
@@ -1405,9 +1439,13 @@
// ----------------------------------------------------------------------------
-
function SetUpBoolean () {
%CheckIsBootstrapping();
+
+ %SetCode($Boolean, BooleanConstructor);
+ %FunctionSetPrototype($Boolean, new $Boolean(false));
+ %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
+
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString,
"valueOf", BooleanValueOf
@@ -1420,17 +1458,15 @@
// ----------------------------------------------------------------------------
// Number
-// Set the Number function and constructor.
-%SetCode($Number, function(x) {
+function NumberConstructor(x) {
var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
if (%_IsConstructCall()) {
%_SetValueOf(this, value);
} else {
return value;
}
-});
+}
-%FunctionSetPrototype($Number, new $Number(0));
// ECMA-262 section 15.7.4.2.
function NumberToString(radix) {
@@ -1568,6 +1604,10 @@
function SetUpNumber() {
%CheckIsBootstrapping();
+
+ %SetCode($Number, NumberConstructor);
+ %FunctionSetPrototype($Number, new $Number(0));
+
%OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
// Set up the constructor property on the Number prototype object.
%SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
@@ -1620,13 +1660,12 @@
// ----------------------------------------------------------------------------
// Function
-$Function.prototype.constructor = $Function;
-
function FunctionSourceString(func) {
while (%IsJSFunctionProxy(func)) {
func = %GetCallTrap(func);
}
+ // TODO(wingo): Print source using function* for generators.
if (!IS_FUNCTION(func)) {
throw new $TypeError('Function.prototype.toString is not generic');
}
@@ -1745,12 +1784,15 @@
return %SetNewFunctionAttributes(f);
}
-%SetCode($Function, NewFunction);
// ----------------------------------------------------------------------------
function SetUpFunction() {
%CheckIsBootstrapping();
+
+ %SetCode($Function, NewFunction);
+ %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
+
InstallFunctions($Function.prototype, DONT_ENUM, $Array(
"bind", FunctionBind,
"toString", FunctionToString
diff --git a/src/v8utils.cc b/src/v8utils.cc
index 58ad4e5..7390d85 100644
--- a/src/v8utils.cc
+++ b/src/v8utils.cc
@@ -105,12 +105,12 @@
char* new_result = NewArray<char>(new_len);
// Copy the existing input into the new array and set the new
// array as the result.
- memcpy(new_result, result, offset * kCharSize);
+ OS::MemCopy(new_result, result, offset * kCharSize);
DeleteArray(result);
result = new_result;
}
// Copy the newly read line into the result.
- memcpy(result + offset, line_buf, len * kCharSize);
+ OS::MemCopy(result + offset, line_buf, len * kCharSize);
offset += len;
}
ASSERT(result != NULL);
@@ -264,7 +264,7 @@
void StringBuilder::AddFormattedList(const char* format, va_list list) {
- ASSERT(!is_finalized() && position_ < buffer_.length());
+ ASSERT(!is_finalized() && position_ <= buffer_.length());
int n = OS::VSNPrintF(buffer_ + position_, format, list);
if (n < 0 || n >= (buffer_.length() - position_)) {
position_ = buffer_.length();
diff --git a/src/v8utils.h b/src/v8utils.h
index b5c8f08..8661f9b 100644
--- a/src/v8utils.h
+++ b/src/v8utils.h
@@ -125,49 +125,126 @@
// ----------------------------------------------------------------------------
// Memory
-// Copies data from |src| to |dst|. The data spans must not overlap.
+// Copies words from |src| to |dst|. The data spans must not overlap.
template <typename T>
-inline void CopyWords(T* dst, T* src, int num_words) {
+inline void CopyWords(T* dst, const T* src, size_t num_words) {
STATIC_ASSERT(sizeof(T) == kPointerSize);
- ASSERT(Min(dst, src) + num_words <= Max(dst, src));
+ ASSERT(Min(dst, const_cast<T*>(src)) + num_words <=
+ Max(dst, const_cast<T*>(src)));
ASSERT(num_words > 0);
// Use block copying OS::MemCopy if the segment we're copying is
// enough to justify the extra call/setup overhead.
- static const int kBlockCopyLimit = 16;
- STATIC_ASSERT(kBlockCopyLimit * kPointerSize >= OS::kMinComplexMemCopy);
+ static const size_t kBlockCopyLimit = 16;
- if (num_words >= kBlockCopyLimit) {
- OS::MemCopy(dst, src, num_words * kPointerSize);
- } else {
- int remaining = num_words;
+ if (num_words < kBlockCopyLimit) {
do {
- remaining--;
+ num_words--;
*dst++ = *src++;
- } while (remaining > 0);
+ } while (num_words > 0);
+ } else {
+ OS::MemCopy(dst, src, num_words * kPointerSize);
+ }
+}
+
+
+// Copies words from |src| to |dst|. No restrictions.
+template <typename T>
+inline void MoveWords(T* dst, const T* src, size_t num_words) {
+ STATIC_ASSERT(sizeof(T) == kPointerSize);
+ ASSERT(num_words > 0);
+
+ // Use block copying OS::MemCopy if the segment we're copying is
+ // enough to justify the extra call/setup overhead.
+ static const size_t kBlockCopyLimit = 16;
+
+ if (num_words < kBlockCopyLimit &&
+ ((dst < src) || (dst >= (src + num_words * kPointerSize)))) {
+ T* end = dst + num_words;
+ do {
+ num_words--;
+ *dst++ = *src++;
+ } while (num_words > 0);
+ } else {
+ OS::MemMove(dst, src, num_words * kPointerSize);
}
}
// Copies data from |src| to |dst|. The data spans must not overlap.
template <typename T>
-inline void CopyBytes(T* dst, T* src, size_t num_bytes) {
+inline void CopyBytes(T* dst, const T* src, size_t num_bytes) {
STATIC_ASSERT(sizeof(T) == 1);
- ASSERT(Min(dst, src) + num_bytes <= Max(dst, src));
+ ASSERT(Min(dst, const_cast<T*>(src)) + num_bytes <=
+ Max(dst, const_cast<T*>(src)));
if (num_bytes == 0) return;
// Use block copying OS::MemCopy if the segment we're copying is
// enough to justify the extra call/setup overhead.
static const int kBlockCopyLimit = OS::kMinComplexMemCopy;
- if (num_bytes >= static_cast<size_t>(kBlockCopyLimit)) {
- OS::MemCopy(dst, src, num_bytes);
- } else {
- size_t remaining = num_bytes;
+ if (num_bytes < static_cast<size_t>(kBlockCopyLimit)) {
do {
- remaining--;
+ num_bytes--;
*dst++ = *src++;
- } while (remaining > 0);
+ } while (num_bytes > 0);
+ } else {
+ OS::MemCopy(dst, src, num_bytes);
+ }
+}
+
+
+// Copies data from |src| to |dst|. No restrictions.
+template <typename T>
+inline void MoveBytes(T* dst, const T* src, size_t num_bytes) {
+ STATIC_ASSERT(sizeof(T) == 1);
+ switch (num_bytes) {
+ case 0: return;
+ case 1:
+ *dst = *src;
+ return;
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+ case 2:
+ *reinterpret_cast<uint16_t*>(dst) = *reinterpret_cast<const uint16_t*>(src);
+ return;
+ case 3: {
+ uint16_t part1 = *reinterpret_cast<const uint16_t*>(src);
+ byte part2 = *(src + 2);
+ *reinterpret_cast<uint16_t*>(dst) = part1;
+ *(dst + 2) = part2;
+ return;
+ }
+ case 4:
+ *reinterpret_cast<uint32_t*>(dst) = *reinterpret_cast<const uint32_t*>(src);
+ return;
+ case 5:
+ case 6:
+ case 7:
+ case 8: {
+ uint32_t part1 = *reinterpret_cast<const uint32_t*>(src);
+ uint32_t part2 = *reinterpret_cast<const uint32_t*>(src + num_bytes - 4);
+ *reinterpret_cast<uint32_t*>(dst) = part1;
+ *reinterpret_cast<uint32_t*>(dst + num_bytes - 4) = part2;
+ return;
+ }
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16: {
+ double part1 = *reinterpret_cast<const double*>(src);
+ double part2 = *reinterpret_cast<const double*>(src + num_bytes - 8);
+ *reinterpret_cast<double*>(dst) = part1;
+ *reinterpret_cast<double*>(dst + num_bytes - 8) = part2;
+ return;
+ }
+#endif
+ default:
+ OS::MemMove(dst, src, num_bytes);
+ return;
}
}
@@ -185,6 +262,13 @@
#elif defined(V8_HOST_ARCH_X64)
#define STOS "stosq"
#endif
+#if defined(__native_client__)
+ // This STOS sequence does not validate for x86_64 Native Client.
+ // Here we #undef STOS to force use of the slower C version.
+ // TODO(bradchen): Profile V8 and implement a faster REP STOS
+ // here if the profile indicates it matters.
+#undef STOS
+#endif
#if defined(__GNUC__) && defined(STOS)
asm volatile(
diff --git a/src/version.cc b/src/version.cc
index 43e6958..933e254 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -33,9 +33,9 @@
// NOTE these macros are used by the SCons build script so their names
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
-#define MINOR_VERSION 17
-#define BUILD_NUMBER 16
-#define PATCH_LEVEL 2
+#define MINOR_VERSION 18
+#define BUILD_NUMBER 0
+#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/assembler-x64.cc b/src/x64/assembler-x64.cc
index 57d40f7..25979f9 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -150,9 +150,8 @@
found_by_runtime_probing_only_
= probed_features & ~kDefaultCpuFeatures & ~platform_features;
- // SSE2 and CMOV must be available on an X64 CPU.
+ // CMOV must be available on an X64 CPU.
ASSERT(IsSupported(CPUID));
- ASSERT(IsSupported(SSE2));
ASSERT(IsSupported(CMOV));
delete memory;
@@ -486,9 +485,9 @@
intptr_t pc_delta = desc.buffer - buffer_;
intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
(buffer_ + buffer_size_);
- memmove(desc.buffer, buffer_, desc.instr_size);
- memmove(rc_delta + reloc_info_writer.pos(),
- reloc_info_writer.pos(), desc.reloc_size);
+ OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+ OS::MemMove(rc_delta + reloc_info_writer.pos(),
+ reloc_info_writer.pos(), desc.reloc_size);
// Switch buffers.
if (isolate() != NULL &&
@@ -2602,6 +2601,26 @@
}
+void Assembler::movdqu(const Operand& dst, XMMRegister src) {
+ EnsureSpace ensure_space(this);
+ emit(0xF3);
+ emit_rex_64(src, dst);
+ emit(0x0F);
+ emit(0x7F);
+ emit_sse_operand(src, dst);
+}
+
+
+void Assembler::movdqu(XMMRegister dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ emit(0xF3);
+ emit_rex_64(dst, src);
+ emit(0x0F);
+ emit(0x6F);
+ emit_sse_operand(dst, src);
+}
+
+
void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
ASSERT(CpuFeatures::IsSupported(SSE4_1));
ASSERT(is_uint8(imm8));
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index 49a57e6..2445e23 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -448,7 +448,7 @@
// CpuFeatureScope fscope(assembler, SSE3);
// // Generate SSE3 floating point code.
// } else {
-// // Generate standard x87 or SSE2 floating point code.
+// // Generate standard SSE2 floating point code.
// }
class CpuFeatures : public AllStatic {
public:
@@ -459,7 +459,6 @@
// Check whether a feature is supported by the target CPU.
static bool IsSupported(CpuFeature f) {
ASSERT(initialized_);
- if (f == SSE2 && !FLAG_enable_sse2) return false;
if (f == SSE3 && !FLAG_enable_sse3) return false;
if (f == SSE4_1 && !FLAG_enable_sse4_1) return false;
if (f == CMOV && !FLAG_enable_cmov) return false;
@@ -480,11 +479,11 @@
}
private:
- // Safe defaults include SSE2 and CMOV for X64. It is always available, if
+ // Safe defaults include CMOV for X64. It is always available, if
// anyone checks, but they shouldn't need to check.
// The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
// fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
- static const uint64_t kDefaultCpuFeatures = (1 << SSE2 | 1 << CMOV);
+ static const uint64_t kDefaultCpuFeatures = (1 << CMOV);
#ifdef DEBUG
static bool initialized_;
@@ -1310,6 +1309,9 @@
void movdqa(const Operand& dst, XMMRegister src);
void movdqa(XMMRegister dst, const Operand& src);
+ void movdqu(const Operand& dst, XMMRegister src);
+ void movdqu(XMMRegister dst, const Operand& src);
+
void movapd(XMMRegister dst, XMMRegister src);
void movaps(XMMRegister dst, XMMRegister src);
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 2da3de2..ba7647b 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -1837,21 +1837,7 @@
void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
- // Get the loop depth of the stack guard check. This is recorded in
- // a test(rax, depth) instruction right after the call.
- Label stack_check;
- __ movq(rbx, Operand(rsp, 0)); // return address
- __ movzxbq(rbx, Operand(rbx, 1)); // depth
-
- // Get the loop nesting level at which we allow OSR from the
- // unoptimized code and check if we want to do OSR yet. If not we
- // should perform a stack guard check so we can get interrupts while
- // waiting for on-stack replacement.
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
- __ movq(rcx, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
- __ movq(rcx, FieldOperand(rcx, SharedFunctionInfo::kCodeOffset));
- __ cmpb(rbx, FieldOperand(rcx, Code::kAllowOSRAtLoopNestingLevelOffset));
- __ j(greater, &stack_check);
// Pass the function to optimize as the argument to the on-stack
// replacement runtime function.
@@ -1868,21 +1854,6 @@
__ j(not_equal, &skip, Label::kNear);
__ ret(0);
- // If we decide not to perform on-stack replacement we perform a
- // stack guard check to enable interrupts.
- __ bind(&stack_check);
- Label ok;
- __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
- __ j(above_equal, &ok, Label::kNear);
-
- StackCheckStub stub;
- __ TailCallStub(&stub);
- if (FLAG_debug_code) {
- __ Abort("Unreachable code: returned from tail call.");
- }
- __ bind(&ok);
- __ ret(0);
-
__ bind(&skip);
// Untag the AST id and push it on the stack.
__ SmiToInteger32(rax, rax);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index fffd37f..787c7fb 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_X64)
#include "bootstrapper.h"
+#include "builtins-decls.h"
#include "code-stubs.h"
#include "regexp-macro-assembler.h"
#include "stub-cache.h"
@@ -39,6 +40,18 @@
namespace internal {
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rax, rbx, rcx };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->stack_parameter_count_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -158,9 +171,7 @@
// Get the function info from the stack.
__ movq(rdx, Operand(rsp, 1 * kPointerSize));
- int map_index = (language_mode_ == CLASSIC_MODE)
- ? Context::FUNCTION_MAP_INDEX
- : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+ int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
// Compute the function map in the current native context and set that
// as the map of the allocated object.
@@ -386,165 +397,6 @@
}
-static void GenerateFastCloneShallowArrayCommon(
- MacroAssembler* masm,
- int length,
- FastCloneShallowArrayStub::Mode mode,
- AllocationSiteMode allocation_site_mode,
- Label* fail) {
- // Registers on entry:
- //
- // rcx: boilerplate literal array.
- ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
- // All sizes here are multiples of kPointerSize.
- int elements_size = 0;
- if (length > 0) {
- elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
- ? FixedDoubleArray::SizeFor(length)
- : FixedArray::SizeFor(length);
- }
- int size = JSArray::kSize;
- int allocation_info_start = size;
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- size += AllocationSiteInfo::kSize;
- }
- size += elements_size;
-
- // Allocate both the JS array and the elements array in one big
- // allocation. This avoids multiple limit checks.
- AllocationFlags flags = TAG_OBJECT;
- if (mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS) {
- flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT | flags);
- }
- __ Allocate(size, rax, rbx, rdx, fail, flags);
-
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ LoadRoot(kScratchRegister, Heap::kAllocationSiteInfoMapRootIndex);
- __ movq(FieldOperand(rax, allocation_info_start), kScratchRegister);
- __ movq(FieldOperand(rax, allocation_info_start + kPointerSize), rcx);
- }
-
- // Copy the JS array part.
- for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
- if ((i != JSArray::kElementsOffset) || (length == 0)) {
- __ movq(rbx, FieldOperand(rcx, i));
- __ movq(FieldOperand(rax, i), rbx);
- }
- }
-
- if (length > 0) {
- // Get hold of the elements array of the boilerplate and setup the
- // elements pointer in the resulting object.
- __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
- if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
- __ lea(rdx, Operand(rax, JSArray::kSize + AllocationSiteInfo::kSize));
- } else {
- __ lea(rdx, Operand(rax, JSArray::kSize));
- }
- __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
-
- // Copy the elements array.
- if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) {
- for (int i = 0; i < elements_size; i += kPointerSize) {
- __ movq(rbx, FieldOperand(rcx, i));
- __ movq(FieldOperand(rdx, i), rbx);
- }
- } else {
- ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
- int i;
- for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
- __ movq(rbx, FieldOperand(rcx, i));
- __ movq(FieldOperand(rdx, i), rbx);
- }
- while (i < elements_size) {
- __ movsd(xmm0, FieldOperand(rcx, i));
- __ movsd(FieldOperand(rdx, i), xmm0);
- i += kDoubleSize;
- }
- ASSERT(i == elements_size);
- }
- }
-}
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
- // Stack layout on entry:
- //
- // [rsp + kPointerSize]: constant elements.
- // [rsp + (2 * kPointerSize)]: literal index.
- // [rsp + (3 * kPointerSize)]: literals array.
-
- // Load boilerplate object into rcx and check if we need to create a
- // boilerplate.
- __ movq(rcx, Operand(rsp, 3 * kPointerSize));
- __ movq(rax, Operand(rsp, 2 * kPointerSize));
- SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
- __ movq(rcx,
- FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize));
- __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
- Label slow_case;
- __ j(equal, &slow_case);
-
- FastCloneShallowArrayStub::Mode mode = mode_;
- // rcx is boilerplate object.
- Factory* factory = masm->isolate()->factory();
- if (mode == CLONE_ANY_ELEMENTS) {
- Label double_elements, check_fast_elements;
- __ movq(rbx, FieldOperand(rcx, JSArray::kElementsOffset));
- __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
- factory->fixed_cow_array_map());
- __ j(not_equal, &check_fast_elements);
- GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- __ ret(3 * kPointerSize);
-
- __ bind(&check_fast_elements);
- __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
- factory->fixed_array_map());
- __ j(not_equal, &double_elements);
- GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
- allocation_site_mode_,
- &slow_case);
- __ ret(3 * kPointerSize);
-
- __ bind(&double_elements);
- mode = CLONE_DOUBLE_ELEMENTS;
- // Fall through to generate the code to handle double elements.
- }
-
- if (FLAG_debug_code) {
- const char* message;
- Heap::RootListIndex expected_map_index;
- if (mode == CLONE_ELEMENTS) {
- message = "Expected (writable) fixed array";
- expected_map_index = Heap::kFixedArrayMapRootIndex;
- } else if (mode == CLONE_DOUBLE_ELEMENTS) {
- message = "Expected (writable) fixed double array";
- expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
- } else {
- ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
- message = "Expected copy-on-write fixed array";
- expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
- }
- __ push(rcx);
- __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
- __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
- expected_map_index);
- __ Assert(equal, message);
- __ pop(rcx);
- }
-
- GenerateFastCloneShallowArrayCommon(masm, length_, mode,
- allocation_site_mode_,
- &slow_case);
- __ ret(3 * kPointerSize);
-
- __ bind(&slow_case);
- __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
// The stub expects its argument on the stack and returns its result in tos_:
// zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
@@ -4154,6 +4006,7 @@
void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CEntryStub::GenerateAheadOfTime(isolate);
StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+ StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
// It is important that the store buffer overflow stubs are generated first.
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
}
@@ -4299,12 +4152,19 @@
// Special handling of out of memory exceptions.
JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
- // Retrieve the pending exception and clear the variable.
+ // Retrieve the pending exception.
ExternalReference pending_exception_address(
Isolate::kPendingExceptionAddress, masm->isolate());
Operand pending_exception_operand =
masm->ExternalOperand(pending_exception_address);
__ movq(rax, pending_exception_operand);
+
+ // See if we just retrieved an OOM exception.
+ JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
+
+ // Clear the pending exception.
+ pending_exception_operand =
+ masm->ExternalOperand(pending_exception_address);
__ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
__ movq(pending_exception_operand, rdx);
@@ -4412,6 +4272,11 @@
void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
Label invoke, handler_entry, exit;
Label not_outermost_js, not_outermost_js_2;
+
+#ifdef _WIN64
+ const int kCalleeSaveXMMRegisters = 10;
+ const int kFullXMMRegisterSize = 16;
+#endif
{ // NOLINT. Scope block confuses linter.
MacroAssembler::NoRootArrayScope uninitialized_root_register(masm);
// Set up frame.
@@ -4438,8 +4303,21 @@
__ push(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
#endif
__ push(rbx);
- // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
- // callee save as well.
+
+#ifdef _WIN64
+ // On Win64 XMM6-XMM15 are callee-save
+ __ subq(rsp, Immediate(kCalleeSaveXMMRegisters * kFullXMMRegisterSize));
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 0), xmm6);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 1), xmm7);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 2), xmm8);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 3), xmm9);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 4), xmm10);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 5), xmm11);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 6), xmm12);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 7), xmm13);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 8), xmm14);
+ __ movdqu(Operand(rsp, kFullXMMRegisterSize * 9), xmm15);
+#endif
// Set up the roots and smi constant registers.
// Needs to be done before any further smi loads.
@@ -4529,6 +4407,21 @@
}
// Restore callee-saved registers (X64 conventions).
+#ifdef _WIN64
+ // On Win64 XMM6-XMM15 are callee-save
+ __ movdqu(xmm6, Operand(rsp, kFullXMMRegisterSize * 0));
+ __ movdqu(xmm7, Operand(rsp, kFullXMMRegisterSize * 1));
+ __ movdqu(xmm8, Operand(rsp, kFullXMMRegisterSize * 2));
+ __ movdqu(xmm8, Operand(rsp, kFullXMMRegisterSize * 3));
+ __ movdqu(xmm10, Operand(rsp, kFullXMMRegisterSize * 4));
+ __ movdqu(xmm11, Operand(rsp, kFullXMMRegisterSize * 5));
+ __ movdqu(xmm12, Operand(rsp, kFullXMMRegisterSize * 6));
+ __ movdqu(xmm13, Operand(rsp, kFullXMMRegisterSize * 7));
+ __ movdqu(xmm14, Operand(rsp, kFullXMMRegisterSize * 8));
+ __ movdqu(xmm15, Operand(rsp, kFullXMMRegisterSize * 9));
+ __ addq(rsp, Immediate(kCalleeSaveXMMRegisters * kFullXMMRegisterSize));
+#endif
+
__ pop(rbx);
#ifdef _WIN64
// Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI.
@@ -6775,8 +6668,7 @@
void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
- ASSERT(!Serializer::enabled());
- CEntryStub ces(1, kSaveFPRegs);
+ CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
__ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 0bb02db..bae97cd 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -117,40 +117,39 @@
static const byte kJnsInstruction = 0x79;
-static const byte kJnsOffset = 0x1f;
+static const byte kJnsOffset = 0x1d;
static const byte kCallInstruction = 0xe8;
static const byte kNopByteOne = 0x66;
static const byte kNopByteTwo = 0x90;
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
+// The back edge bookkeeping code matches the pattern:
+//
+// add <profiling_counter>, <-delta>
+// jns ok
+// call <stack guard>
+// ok:
+//
+// We will patch away the branch so the code is:
+//
+// add <profiling_counter>, <-delta> ;; Not changed
+// nop
+// nop
+// call <on-stack replacment>
+// ok:
+
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ // Turn the jump into nops.
Address call_target_address = pc_after - kIntSize;
- ASSERT_EQ(check_code->entry(),
- Assembler::target_address_at(call_target_address));
- // The back edge bookkeeping code matches the pattern:
- //
- // add <profiling_counter>, <-delta>
- // jns ok
- // call <stack guard>
- // test rax, <loop nesting depth>
- // ok: ...
- //
- // We will patch away the branch so the code is:
- //
- // add <profiling_counter>, <-delta> ;; Not changed
- // nop
- // nop
- // call <on-stack replacment>
- // test rax, <loop nesting depth>
- // ok:
- //
- ASSERT_EQ(kJnsInstruction, *(call_target_address - 3));
- ASSERT_EQ(kJnsOffset, *(call_target_address - 2));
- ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
*(call_target_address - 3) = kNopByteOne;
*(call_target_address - 2) = kNopByteTwo;
+ // Replace the call address.
Assembler::set_target_address_at(call_target_address,
replacement_code->entry());
@@ -159,28 +158,50 @@
}
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code) {
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ ASSERT(InterruptCodeIsPatched(unoptimized_code,
+ pc_after,
+ interrupt_code,
+ replacement_code));
+ // Restore the original jump.
Address call_target_address = pc_after - kIntSize;
- ASSERT(replacement_code->entry() ==
- Assembler::target_address_at(call_target_address));
- // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to
- // restore the conditional branch.
- ASSERT_EQ(kNopByteOne, *(call_target_address - 3));
- ASSERT_EQ(kNopByteTwo, *(call_target_address - 2));
- ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
*(call_target_address - 3) = kJnsInstruction;
*(call_target_address - 2) = kJnsOffset;
+ // Restore the original call address.
Assembler::set_target_address_at(call_target_address,
- check_code->entry());
+ interrupt_code->entry());
- check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
- unoptimized_code, call_target_address, check_code);
+ interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+ unoptimized_code, call_target_address, interrupt_code);
}
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+ Address pc_after,
+ Code* interrupt_code,
+ Code* replacement_code) {
+ Address call_target_address = pc_after - kIntSize;
+ ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
+ if (*(call_target_address - 3) == kNopByteOne) {
+ ASSERT(replacement_code->entry() ==
+ Assembler::target_address_at(call_target_address));
+ ASSERT_EQ(kNopByteTwo, *(call_target_address - 2));
+ return true;
+ } else {
+ ASSERT_EQ(interrupt_code->entry(),
+ Assembler::target_address_at(call_target_address));
+ ASSERT_EQ(kJnsInstruction, *(call_target_address - 3));
+ ASSERT_EQ(kJnsOffset, *(call_target_address - 2));
+ return false;
+ }
+}
+#endif // DEBUG
+
+
static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
ByteArray* translations = data->TranslationByteArray();
int length = data->DeoptCount();
diff --git a/src/x64/frames-x64.h b/src/x64/frames-x64.h
index 53c3459..14cc5b8 100644
--- a/src/x64/frames-x64.h
+++ b/src/x64/frames-x64.h
@@ -48,18 +48,6 @@
// ----------------------------------------------------
-class StackHandlerConstants : public AllStatic {
- public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kCodeOffset = 1 * kPointerSize;
- static const int kStateOffset = 2 * kPointerSize;
- static const int kContextOffset = 3 * kPointerSize;
- static const int kFPOffset = 4 * kPointerSize;
-
- static const int kSize = kFPOffset + kPointerSize;
-};
-
-
class EntryFrameConstants : public AllStatic {
public:
#ifdef _WIN64
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 322479d..564c3de 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -160,6 +160,8 @@
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
if (locals_count == 1) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
} else if (locals_count > 1) {
@@ -347,13 +349,6 @@
// the deoptimization input data found in the optimized code.
RecordBackEdge(stmt->OsrEntryId());
- // Loop stack checks can be patched to perform on-stack replacement. In
- // order to decide whether or not to perform OSR we embed the loop depth
- // in a test instruction after the call so we can extract it from the OSR
- // builtin.
- ASSERT(loop_depth() > 0);
- __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
-
EmitProfilingCounterReset();
__ bind(&ok);
@@ -1240,7 +1235,7 @@
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->language_mode());
+ FastNewClosureStub stub(info->language_mode(), info->is_generator());
__ Push(info);
__ CallStub(&stub);
} else {
@@ -1695,24 +1690,33 @@
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
- __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
- __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
- __ Push(Smi::FromInt(expr->literal_index()));
- __ Push(constant_elements);
Heap* heap = isolate()->heap();
if (has_constant_fast_elements &&
constant_elements_values->map() == heap->fixed_cow_array_map()) {
// If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
// change, so it's possible to specialize the stub in advance.
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
+ __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ __ movq(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
+ __ Move(rbx, Smi::FromInt(expr->literal_index()));
+ __ Move(rcx, constant_elements);
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
DONT_TRACK_ALLOCATION_SITE,
length);
__ CallStub(&stub);
} else if (expr->depth() > 1) {
+ __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
+ __ Push(Smi::FromInt(expr->literal_index()));
+ __ Push(constant_elements);
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
- } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ } else if (Serializer::enabled() ||
+ length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
+ __ Push(Smi::FromInt(expr->literal_index()));
+ __ Push(constant_elements);
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -1729,6 +1733,10 @@
allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
}
+ __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ __ movq(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
+ __ Move(rbx, Smi::FromInt(expr->literal_index()));
+ __ Move(rcx, constant_elements);
FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
__ CallStub(&stub);
}
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 817a9d3..6fc56ed 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -118,7 +118,7 @@
// issues when the stack allocated buffer goes out of scope.
int length = builder.position();
Vector<char> copy = Vector<char>::New(length + 1);
- memcpy(copy.start(), builder.Finalize(), copy.length());
+ OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
masm()->RecordComment(copy.start());
}
@@ -1793,6 +1793,8 @@
break;
case Token::DIV:
__ divsd(left, right);
+ // Don't delete this mov. It may improve performance on some CPUs,
+ // when there is a mulsd depending on the result
__ movaps(left, left);
break;
case Token::MOD:
@@ -3366,7 +3368,7 @@
}
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
Register input_reg = ToRegister(instr->value());
__ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
@@ -3418,7 +3420,7 @@
}
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
Register input_reg = ToRegister(instr->value());
__ testl(input_reg, input_reg);
Label is_positive;
@@ -3429,19 +3431,18 @@
}
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
// Class for deferred case.
class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
public:
- DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
- LUnaryMathOperation* instr)
+ DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
}
virtual LInstruction* instr() { return instr_; }
private:
- LUnaryMathOperation* instr_;
+ LMathAbs* instr_;
};
ASSERT(instr->value()->Equals(instr->result()));
@@ -3469,7 +3470,7 @@
}
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
@@ -3528,7 +3529,7 @@
}
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathRound(LMathRound* instr) {
const XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
@@ -3589,14 +3590,14 @@
}
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
XMMRegister input_reg = ToDoubleRegister(instr->value());
ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
__ sqrtsd(input_reg, input_reg);
}
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
XMMRegister xmm_scratch = xmm0;
XMMRegister input_reg = ToDoubleRegister(instr->value());
ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
@@ -3763,7 +3764,7 @@
}
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::UNTAGGED);
@@ -3771,7 +3772,7 @@
}
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::TAN,
TranscendentalCacheStub::UNTAGGED);
@@ -3779,7 +3780,7 @@
}
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
@@ -3787,7 +3788,7 @@
}
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
@@ -3795,42 +3796,6 @@
}
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
- switch (instr->op()) {
- case kMathAbs:
- DoMathAbs(instr);
- break;
- case kMathFloor:
- DoMathFloor(instr);
- break;
- case kMathRound:
- DoMathRound(instr);
- break;
- case kMathSqrt:
- DoMathSqrt(instr);
- break;
- case kMathPowHalf:
- DoMathPowHalf(instr);
- break;
- case kMathCos:
- DoMathCos(instr);
- break;
- case kMathSin:
- DoMathSin(instr);
- break;
- case kMathTan:
- DoMathTan(instr);
- break;
- case kMathLog:
- DoMathLog(instr);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(rdi));
ASSERT(instr->HasPointerMap());
@@ -4977,7 +4942,6 @@
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
- ASSERT(instr->temp()->Equals(instr->result()));
Register reg = ToRegister(instr->temp());
ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
@@ -4989,7 +4953,6 @@
for (int i = 0; i < maps->length(); i++) {
prototype_maps_.Add(maps->at(i), info()->zone());
}
- __ LoadHeapObject(reg, prototypes->at(prototypes->length() - 1));
} else {
for (int i = 0; i < prototypes->length(); i++) {
__ LoadHeapObject(reg, prototypes->at(i));
@@ -5114,11 +5077,11 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+ }
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- }
__ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
@@ -5141,7 +5104,13 @@
PushSafepointRegistersScope scope(this);
__ Integer32ToSmi(size, size);
__ push(size);
- CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+ if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInOldPointerSpace, 1, instr);
+ } else {
+ CallRuntimeFromDeferred(
+ Runtime::kAllocateInNewSpace, 1, instr);
+ }
__ StoreToSafepointRegisterSlot(result, rax);
}
@@ -5169,26 +5138,33 @@
DeoptimizeIf(not_equal, instr->environment());
}
- // Set up the parameters to the stub/runtime call.
- __ PushHeapObject(literals);
- __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
- // Boilerplate already exists, constant elements are never accessed.
- // Pass an empty fixed array.
- __ Push(isolate()->factory()->empty_fixed_array());
-
- // Pick the right runtime function or stub to call.
+ // Set up the parameters to the stub/runtime call and pick the right
+ // runtime function or stub to call. Boilerplate already exists,
+ // constant elements are never accessed, pass an empty fixed array.
int length = instr->hydrogen()->length();
if (instr->hydrogen()->IsCopyOnWrite()) {
ASSERT(instr->hydrogen()->depth() == 1);
+ __ LoadHeapObject(rax, literals);
+ __ Move(rbx, Smi::FromInt(instr->hydrogen()->literal_index()));
+ __ Move(rcx, isolate()->factory()->empty_fixed_array());
FastCloneShallowArrayStub::Mode mode =
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else if (instr->hydrogen()->depth() > 1) {
+ __ PushHeapObject(literals);
+ __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
+ __ Push(isolate()->factory()->empty_fixed_array());
CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ __ PushHeapObject(literals);
+ __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
+ __ Push(isolate()->factory()->empty_fixed_array());
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
} else {
+ __ LoadHeapObject(rax, literals);
+ __ Move(rbx, Smi::FromInt(instr->hydrogen()->literal_index()));
+ __ Move(rcx, isolate()->factory()->empty_fixed_array());
FastCloneShallowArrayStub::Mode mode =
boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
@@ -5199,163 +5175,6 @@
}
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
- Register result,
- Register source,
- int* offset,
- AllocationSiteMode mode) {
- ASSERT(!source.is(rcx));
- ASSERT(!result.is(rcx));
-
- bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
- object->map()->CanTrackAllocationSite();
-
- // Only elements backing stores for non-COW arrays need to be copied.
- Handle<FixedArrayBase> elements(object->elements());
- bool has_elements = elements->length() > 0 &&
- elements->map() != isolate()->heap()->fixed_cow_array_map();
-
- // Increase the offset so that subsequent objects end up right after
- // this object and its backing store.
- int object_offset = *offset;
- int object_size = object->map()->instance_size();
- int elements_size = has_elements ? elements->Size() : 0;
- int elements_offset = *offset + object_size;
- if (create_allocation_site_info) {
- elements_offset += AllocationSiteInfo::kSize;
- *offset += AllocationSiteInfo::kSize;
- }
-
- *offset += object_size + elements_size;
-
- // Copy object header.
- ASSERT(object->properties()->length() == 0);
- int inobject_properties = object->map()->inobject_properties();
- int header_size = object_size - inobject_properties * kPointerSize;
- for (int i = 0; i < header_size; i += kPointerSize) {
- if (has_elements && i == JSObject::kElementsOffset) {
- __ lea(rcx, Operand(result, elements_offset));
- } else {
- __ movq(rcx, FieldOperand(source, i));
- }
- __ movq(FieldOperand(result, object_offset + i), rcx);
- }
-
- // Copy in-object properties.
- for (int i = 0; i < inobject_properties; i++) {
- int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
- Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
- isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ lea(rcx, Operand(result, *offset));
- __ movq(FieldOperand(result, total_offset), rcx);
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
- __ movq(FieldOperand(result, total_offset), rcx);
- } else {
- __ movq(rcx, value, RelocInfo::NONE64);
- __ movq(FieldOperand(result, total_offset), rcx);
- }
- }
-
- // Build Allocation Site Info if desired
- if (create_allocation_site_info) {
- __ LoadRoot(kScratchRegister, Heap::kAllocationSiteInfoMapRootIndex);
- __ movq(FieldOperand(result, object_size), kScratchRegister);
- __ movq(FieldOperand(result, object_size + kPointerSize), source);
- }
-
- if (has_elements) {
- // Copy elements backing store header.
- __ LoadHeapObject(source, elements);
- for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
- __ movq(rcx, FieldOperand(source, i));
- __ movq(FieldOperand(result, elements_offset + i), rcx);
- }
-
- // Copy elements backing store content.
- int elements_length = elements->length();
- if (elements->IsFixedDoubleArray()) {
- Handle<FixedDoubleArray> double_array =
- Handle<FixedDoubleArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int64_t value = double_array->get_representation(i);
- int total_offset =
- elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
- __ movq(rcx, value, RelocInfo::NONE64);
- __ movq(FieldOperand(result, total_offset), rcx);
- }
- } else if (elements->IsFixedArray()) {
- Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
- for (int i = 0; i < elements_length; i++) {
- int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value(fast_elements->get(i), isolate());
- if (value->IsJSObject()) {
- Handle<JSObject> value_object = Handle<JSObject>::cast(value);
- __ lea(rcx, Operand(result, *offset));
- __ movq(FieldOperand(result, total_offset), rcx);
- __ LoadHeapObject(source, value_object);
- EmitDeepCopy(value_object, result, source, offset,
- DONT_TRACK_ALLOCATION_SITE);
- } else if (value->IsHeapObject()) {
- __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
- __ movq(FieldOperand(result, total_offset), rcx);
- } else {
- __ movq(rcx, value, RelocInfo::NONE64);
- __ movq(FieldOperand(result, total_offset), rcx);
- }
- }
- } else {
- UNREACHABLE();
- }
- }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
- int size = instr->hydrogen()->total_size();
- ElementsKind boilerplate_elements_kind =
- instr->hydrogen()->boilerplate()->GetElementsKind();
-
- // Deopt if the array literal boilerplate ElementsKind is of a type different
- // than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
- if (CanTransitionToMoreGeneralFastElementsKind(
- boilerplate_elements_kind, true)) {
- __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
- __ movq(rcx, FieldOperand(rbx, HeapObject::kMapOffset));
- // Load the map's "bit field 2".
- __ movb(rcx, FieldOperand(rcx, Map::kBitField2Offset));
- // Retrieve elements_kind from bit field 2.
- __ and_(rcx, Immediate(Map::kElementsKindMask));
- __ cmpb(rcx, Immediate(boilerplate_elements_kind <<
- Map::kElementsKindShift));
- DeoptimizeIf(not_equal, instr->environment());
- }
-
- // Allocate all objects that are part of the literal in one big
- // allocation. This avoids multiple limit checks.
- Label allocated, runtime_allocate;
- __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
- __ jmp(&allocated);
-
- __ bind(&runtime_allocate);
- __ Push(Smi::FromInt(size));
- CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
- __ bind(&allocated);
- int offset = 0;
- __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
- EmitDeepCopy(instr->hydrogen()->boilerplate(), rax, rbx, &offset,
- instr->hydrogen()->allocation_site_mode());
- ASSERT_EQ(size, offset);
-}
-
-
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
Handle<FixedArray> literals(instr->environment()->closure()->literals());
Handle<FixedArray> constant_properties =
@@ -5458,7 +5277,8 @@
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode());
+ FastNewClosureStub stub(shared_info->language_mode(),
+ shared_info->is_generator());
__ Push(shared_info);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else {
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 5809296..e857606 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -111,7 +111,7 @@
void DoDeferredNumberTagD(LNumberTagD* instr);
void DoDeferredNumberTagU(LNumberTagU* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
- void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+ void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -258,17 +258,7 @@
uint32_t offset,
uint32_t additional_index = 0);
- // Specific math operations - used from DoUnaryMathOperation.
- void EmitIntegerMathAbs(LUnaryMathOperation* instr);
- void DoMathAbs(LUnaryMathOperation* instr);
- void DoMathFloor(LUnaryMathOperation* instr);
- void DoMathRound(LUnaryMathOperation* instr);
- void DoMathSqrt(LUnaryMathOperation* instr);
- void DoMathPowHalf(LUnaryMathOperation* instr);
- void DoMathLog(LUnaryMathOperation* instr);
- void DoMathTan(LUnaryMathOperation* instr);
- void DoMathCos(LUnaryMathOperation* instr);
- void DoMathSin(LUnaryMathOperation* instr);
+ void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers,
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 9a3166e..ba29ed9 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -304,17 +304,6 @@
}
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
- stream->Add("/%s ", hydrogen()->OpName());
- value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
- value()->PrintTo(stream);
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -1130,41 +1119,97 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
- BuiltinFunctionId op = instr->op();
- if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
- LOperand* input = UseFixedDouble(instr->value(), xmm1);
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
- return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
- } else if (op == kMathExp) {
- ASSERT(instr->representation().IsDouble());
- ASSERT(instr->value()->representation().IsDouble());
- LOperand* value = UseTempRegister(instr->value());
- LOperand* temp1 = TempRegister();
- LOperand* temp2 = TempRegister();
- LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
- return DefineAsRegister(result);
- } else {
- LOperand* input = UseRegisterAtStart(instr->value());
- LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
- switch (op) {
- case kMathAbs:
- return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
- case kMathFloor:
- return AssignEnvironment(DefineAsRegister(result));
- case kMathRound:
- return AssignEnvironment(DefineAsRegister(result));
- case kMathSqrt:
- return DefineSameAsFirst(result);
- case kMathPowHalf:
- return DefineSameAsFirst(result);
- default:
- UNREACHABLE();
- return NULL;
- }
+ switch (instr->op()) {
+ case kMathFloor: return DoMathFloor(instr);
+ case kMathRound: return DoMathRound(instr);
+ case kMathAbs: return DoMathAbs(instr);
+ case kMathLog: return DoMathLog(instr);
+ case kMathSin: return DoMathSin(instr);
+ case kMathCos: return DoMathCos(instr);
+ case kMathTan: return DoMathTan(instr);
+ case kMathExp: return DoMathExp(instr);
+ case kMathSqrt: return DoMathSqrt(instr);
+ case kMathPowHalf: return DoMathPowHalf(instr);
+ default:
+ UNREACHABLE();
+ return NULL;
}
}
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathFloor* result = new(zone()) LMathFloor(input);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathRound* result = new(zone()) LMathRound(input);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathAbs* result = new(zone()) LMathAbs(input);
+ return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathLog* result = new(zone()) LMathLog(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathSin* result = new(zone()) LMathSin(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathCos* result = new(zone()) LMathCos(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+ LOperand* input = UseFixedDouble(instr->value(), xmm1);
+ LMathTan* result = new(zone()) LMathTan(input);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* value = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
+ return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathSqrt* result = new(zone()) LMathSqrt(input);
+ return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+ LOperand* input = UseRegisterAtStart(instr->value());
+ LMathPowHalf* result = new(zone()) LMathPowHalf(input);
+ return DefineSameAsFirst(result);
+}
+
+
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
LOperand* key = UseFixed(instr->key(), rcx);
@@ -1843,7 +1888,7 @@
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
LUnallocated* temp = TempRegister();
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
- return AssignEnvironment(Define(result, temp));
+ return AssignEnvironment(result);
}
@@ -2252,11 +2297,6 @@
}
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
- return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, rax), instr);
-}
-
-
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, rax), instr);
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 051f9a4..54f117c 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -97,7 +97,6 @@
V(DoubleToI) \
V(DummyUse) \
V(ElementsKind) \
- V(FastLiteral) \
V(FixedArrayBaseLength) \
V(MapEnumLength) \
V(FunctionLiteral) \
@@ -134,9 +133,18 @@
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MathAbs) \
+ V(MathCos) \
V(MathExp) \
+ V(MathFloor) \
V(MathFloorOfDiv) \
+ V(MathLog) \
V(MathMinMax) \
+ V(MathPowHalf) \
+ V(MathRound) \
+ V(MathSin) \
+ V(MathSqrt) \
+ V(MathTan) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -178,7 +186,6 @@
V(TrapAllocationMemento) \
V(Typeof) \
V(TypeofIsAndBranch) \
- V(UnaryMathOperation) \
V(UnknownOSRValue) \
V(ValueOf) \
V(ForInPrepareMap) \
@@ -650,19 +657,90 @@
};
-class LUnaryMathOperation: public LTemplateInstruction<1, 1, 0> {
+class LMathFloor: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LUnaryMathOperation(LOperand* value) {
+ explicit LMathFloor(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
- DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+ DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
- virtual void PrintDataTo(StringStream* stream);
- BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathRound: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathRound(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathAbs(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathLog(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSin(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathCos(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathTan(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
};
@@ -680,8 +758,30 @@
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
- virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathSqrt(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LMathPowHalf(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
};
@@ -1250,7 +1350,7 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+ DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
};
@@ -2158,7 +2258,7 @@
};
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
public:
explicit LCheckPrototypeMaps(LOperand* temp) {
temps_[0] = temp;
@@ -2267,13 +2367,6 @@
};
-class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
- public:
- DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
- DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
@@ -2505,6 +2598,17 @@
static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
+ LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+ LInstruction* DoMathRound(HUnaryMathOperation* instr);
+ LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+ LInstruction* DoMathLog(HUnaryMathOperation* instr);
+ LInstruction* DoMathSin(HUnaryMathOperation* instr);
+ LInstruction* DoMathCos(HUnaryMathOperation* instr);
+ LInstruction* DoMathTan(HUnaryMathOperation* instr);
+ LInstruction* DoMathExp(HUnaryMathOperation* instr);
+ LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+ LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
private:
enum Status {
UNUSED,
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 6c1c19d..5865924 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -899,7 +899,6 @@
}
// R12 to r15 are callee save on all platforms.
if (fp_mode == kSaveFPRegs) {
- CpuFeatureScope scope(this, SSE2);
subq(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
XMMRegister reg = XMMRegister::from_code(i);
@@ -914,7 +913,6 @@
Register exclusion2,
Register exclusion3) {
if (fp_mode == kSaveFPRegs) {
- CpuFeatureScope scope(this, SSE2);
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
XMMRegister reg = XMMRegister::from_code(i);
movsd(reg, Operand(rsp, i * kDoubleSize));
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 7e900db..41e5b88 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -712,25 +712,41 @@
}
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+ Handle<GlobalObject> global,
+ Handle<Name> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ __ Move(scratch, cell);
+ __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+ masm->isolate()->factory()->the_hole_value());
+ __ j(not_equal, miss);
+}
+
+
// 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,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label,
- Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label,
+ Label* miss_restore_name) {
// Check that the map of the object hasn't changed.
- CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
- : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK, mode);
+ miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -738,7 +754,7 @@
}
// Check that we are allowed to write this.
- if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+ if (object->GetPrototype()->IsJSObject()) {
JSObject* holder;
// holder == object indicates that no property was found.
if (lookup->holder() != *object) {
@@ -756,12 +772,18 @@
// If no property was found, and the holder (the last object in the
// prototype chain) is in slow mode, we need to do a negative lookup on the
// holder.
- if (lookup->holder() == *object &&
- !holder->HasFastProperties() &&
- !holder->IsJSGlobalProxy() &&
- !holder->IsJSGlobalObject()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ if (lookup->holder() == *object) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm,
+ Handle<GlobalObject>(GlobalObject::cast(holder)),
+ name,
+ scratch1,
+ miss_restore_name);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
}
@@ -770,7 +792,7 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+ if (object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ pop(scratch1); // Return address.
@@ -786,32 +808,29 @@
return;
}
- int index;
- if (!transition.is_null()) {
- // Update the map of the object.
- __ Move(scratch1, transition);
- __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
+ // Update the map of the object.
+ __ Move(scratch1, transition);
+ __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
- // Update the write barrier for the map field and pass the now unused
- // name_reg as scratch register.
- __ RecordWriteField(receiver_reg,
- HeapObject::kMapOffset,
- scratch1,
- name_reg,
- kDontSaveFPRegs,
- OMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- index = transition->instance_descriptors()->GetFieldIndex(
- transition->LastAdded());
- } else {
- index = lookup->GetFieldIndex().field_index();
- }
+ // Update the write barrier for the map field and pass the now unused
+ // name_reg as scratch register.
+ __ RecordWriteField(receiver_reg,
+ HeapObject::kMapOffset,
+ scratch1,
+ name_reg,
+ kDontSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ int index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= object->map()->inobject_properties();
+ // TODO(verwaest): Share this code as a code stub.
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -842,21 +861,65 @@
}
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
- Handle<GlobalObject> global,
- Handle<Name> name,
- Register scratch,
- Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
- GlobalObject::EnsurePropertyCell(global, name);
- ASSERT(cell->value()->IsTheHole());
- __ Move(scratch, cell);
- __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
- masm->isolate()->factory()->the_hole_value());
- __ j(not_equal, miss);
+// 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,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ // Check that the map of the object hasn't changed.
+ __ CheckMap(receiver_reg, Handle<Map>(object->map()),
+ miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ int index = lookup->GetFieldIndex().field_index();
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ // TODO(verwaest): Share this code as a code stub.
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ movq(FieldOperand(receiver_reg, offset), value_reg);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ movq(name_reg, value_reg);
+ __ RecordWriteField(
+ receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array (optimistically).
+ __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ movq(FieldOperand(scratch1, offset), value_reg);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ movq(name_reg, value_reg);
+ __ RecordWriteField(
+ scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs);
+ }
+
+ // Return the value (register rax).
+ ASSERT(value_reg.is(rax));
+ __ ret(0);
}
@@ -1077,7 +1140,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+ HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1085,13 +1148,6 @@
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- if (!last->HasFastProperties()) {
- __ movq(scratch2(), FieldOperand(reg, HeapObject::kMapOffset));
- __ movq(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset));
- __ Cmp(scratch2(), isolate()->factory()->null_value());
- __ j(not_equal, &miss);
- }
-
HandlerFrontendFooter(success, &miss);
}