Version 3.4.8
Ensure 16-byte stack alignment on Solaris (issue 1505).
Fix "illegal access" when calling parseInt with a radix that is not a smi. (issue 1246).
git-svn-id: http://v8.googlecode.com/svn/trunk@8466 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index 29d4ecd..df99fdc 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -45,6 +45,7 @@
#include "json-parser.h"
#include "liveedit.h"
#include "liveobjectlist-inl.h"
+#include "misc-intrinsics.h"
#include "parser.h"
#include "platform.h"
#include "runtime-profiler.h"
@@ -1236,9 +1237,8 @@
RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Handle<Object> initial_value(args[3], isolate);
- // Declarations are always done in the function context.
- context = Handle<Context>(context->fcontext());
- ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
+ // Declarations are always done in a function or global context.
+ context = Handle<Context>(context->declaration_context());
int index;
PropertyAttributes attributes;
@@ -1525,8 +1525,8 @@
CONVERT_ARG_CHECKED(Context, context, 1);
Handle<String> name(String::cast(args[2]));
- // Initializations are always done in the function context.
- context = Handle<Context>(context->fcontext());
+ // Initializations are always done in a function or global context.
+ context = Handle<Context>(context->declaration_context());
int index;
PropertyAttributes attributes;
@@ -1547,14 +1547,12 @@
// In that case, the initialization behaves like a normal assignment
// to property 'x'.
if (index >= 0) {
- // Property was found in a context.
if (holder->IsContext()) {
- // The holder cannot be the function context. If it is, there
- // should have been a const redeclaration error when declaring
- // the const property.
- ASSERT(!holder.is_identical_to(context));
- if ((attributes & READ_ONLY) == 0) {
- Handle<Context>::cast(holder)->set(index, *value);
+ // Property was found in a context. Perform the assignment if we
+ // found some non-constant or an uninitialized constant.
+ Handle<Context> context = Handle<Context>::cast(holder);
+ if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
+ context->set(index, *value);
}
} else {
// The holder is an arguments object.
@@ -6645,50 +6643,69 @@
// If the integers are equal so are the string representations.
if (x_value == y_value) return Smi::FromInt(EQUAL);
- // If one of the integers are zero the normal integer order is the
+ // If one of the integers is zero the normal integer order is the
// same as the lexicographic order of the string representations.
- if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
+ if (x_value == 0 || y_value == 0)
+ return Smi::FromInt(x_value < y_value ? LESS : GREATER);
// If only one of the integers is negative the negative number is
// smallest because the char code of '-' is less than the char code
// of any digit. Otherwise, we make both values positive.
+
+ // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
+ // architectures using 32-bit Smis.
+ uint32_t x_scaled = x_value;
+ uint32_t y_scaled = y_value;
if (x_value < 0 || y_value < 0) {
if (y_value >= 0) return Smi::FromInt(LESS);
if (x_value >= 0) return Smi::FromInt(GREATER);
- x_value = -x_value;
- y_value = -y_value;
+ x_scaled = -x_value;
+ y_scaled = -y_value;
}
- // Arrays for the individual characters of the two Smis. Smis are
- // 31 bit integers and 10 decimal digits are therefore enough.
- // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
- int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
- int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
+ static const uint32_t kPowersOf10[] = {
+ 1, 10, 100, 1000, 10*1000, 100*1000,
+ 1000*1000, 10*1000*1000, 100*1000*1000,
+ 1000*1000*1000
+ };
+ // If the integers have the same number of decimal digits they can be
+ // compared directly as the numeric order is the same as the
+ // lexicographic order. If one integer has fewer digits, it is scaled
+ // by some power of 10 to have the same number of digits as the longer
+ // integer. If the scaled integers are equal it means the shorter
+ // integer comes first in the lexicographic order.
- // Convert the integers to arrays of their decimal digits.
- int x_index = 0;
- int y_index = 0;
- while (x_value > 0) {
- x_elms[x_index++] = x_value % 10;
- x_value /= 10;
- }
- while (y_value > 0) {
- y_elms[y_index++] = y_value % 10;
- y_value /= 10;
+ // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+ int x_log2 = IntegerLog2(x_scaled);
+ int x_log10 = ((x_log2 + 1) * 1233) >> 12;
+ x_log10 -= x_scaled < kPowersOf10[x_log10];
+
+ int y_log2 = IntegerLog2(y_scaled);
+ int y_log10 = ((y_log2 + 1) * 1233) >> 12;
+ y_log10 -= y_scaled < kPowersOf10[y_log10];
+
+ int tie = EQUAL;
+
+ if (x_log10 < y_log10) {
+ // X has fewer digits. We would like to simply scale up X but that
+ // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
+ // be scaled up to 9_000_000_000. So we scale up by the next
+ // smallest power and scale down Y to drop one digit. It is OK to
+ // drop one digit from the longer integer since the final digit is
+ // past the length of the shorter integer.
+ x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
+ y_scaled /= 10;
+ tie = LESS;
+ } else if (y_log10 < x_log10) {
+ y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
+ x_scaled /= 10;
+ tie = GREATER;
}
- // Loop through the arrays of decimal digits finding the first place
- // where they differ.
- while (--x_index >= 0 && --y_index >= 0) {
- int diff = x_elms[x_index] - y_elms[y_index];
- if (diff != 0) return Smi::FromInt(diff);
- }
-
- // If one array is a suffix of the other array, the longest array is
- // the representation of the largest of the Smis in the
- // lexicographic ordering.
- return Smi::FromInt(x_index - y_index);
+ if (x_scaled < y_scaled) return Smi::FromInt(LESS);
+ if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
+ return Smi::FromInt(tie);
}
@@ -8052,7 +8069,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
NoHandleAllocation ha;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 2);
JSObject* extension_object;
if (args[0]->IsJSObject()) {
extension_object = JSObject::cast(args[0]);
@@ -8073,9 +8090,20 @@
}
}
+ JSFunction* function;
+ if (args[1]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the global context.
+ function = isolate->context()->global_context()->closure();
+ } else {
+ function = JSFunction::cast(args[1]);
+ }
+
Context* context;
MaybeObject* maybe_context =
- isolate->heap()->AllocateWithContext(isolate->context(),
+ isolate->heap()->AllocateWithContext(function,
+ isolate->context(),
extension_object);
if (!maybe_context->To(&context)) return maybe_context;
isolate->set_context(context);
@@ -8085,12 +8113,22 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
NoHandleAllocation ha;
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 3);
String* name = String::cast(args[0]);
Object* thrown_object = args[1];
+ JSFunction* function;
+ if (args[2]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the global context.
+ function = isolate->context()->global_context()->closure();
+ } else {
+ function = JSFunction::cast(args[2]);
+ }
Context* context;
MaybeObject* maybe_context =
- isolate->heap()->AllocateCatchContext(isolate->context(),
+ isolate->heap()->AllocateCatchContext(function,
+ isolate->context(),
name,
thrown_object);
if (!maybe_context->To(&context)) return maybe_context;
@@ -9986,9 +10024,6 @@
Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ScopeInfo<> info(*scope_info);
- // Get the nearest enclosing function context.
- Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
-
// Get the locals names and values into a temporary array.
//
// TODO(1240907): Hide compiler-introduced stack variables
@@ -9997,11 +10032,6 @@
Handle<FixedArray> locals =
isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
- // Fill in the names of the locals.
- for (int i = 0; i < info.NumberOfLocals(); i++) {
- locals->set(i * 2, *info.LocalName(i));
- }
-
// Fill in the values of the locals.
if (is_optimized_frame) {
// If we are inspecting an optimized frame use undefined as the
@@ -10010,15 +10040,22 @@
// TODO(1140): We should be able to get the correct values
// for locals in optimized frames.
for (int i = 0; i < info.NumberOfLocals(); i++) {
+ locals->set(i * 2, *info.LocalName(i));
locals->set(i * 2 + 1, isolate->heap()->undefined_value());
}
} else {
- for (int i = 0; i < info.number_of_stack_slots(); i++) {
- // Get the value from the stack.
+ int i = 0;
+ for (; i < info.number_of_stack_slots(); ++i) {
+ // Use the value from the stack.
+ locals->set(i * 2, *info.LocalName(i));
locals->set(i * 2 + 1, it.frame()->GetExpression(i));
}
- for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
+ // Get the context containing declarations.
+ Handle<Context> context(
+ Context::cast(it.frame()->context())->declaration_context());
+ for (; i < info.NumberOfLocals(); ++i) {
Handle<String> name = info.LocalName(i);
+ locals->set(i * 2, *name);
locals->set(i * 2 + 1,
context->get(scope_info->ContextSlotIndex(*name, NULL)));
}
@@ -10239,7 +10276,7 @@
// Third fill all context locals.
Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->fcontext());
+ Handle<Context> function_context(frame_context->declaration_context());
if (!CopyContextLocalsToScopeObject(isolate,
serialized_scope_info, scope_info,
function_context, local_scope)) {
@@ -10971,6 +11008,7 @@
// Creates a copy of the with context chain. The copy of the context chain is
// is linked to the function context supplied.
static Handle<Context> CopyWithContextChain(Isolate* isolate,
+ Handle<JSFunction> function,
Handle<Context> current,
Handle<Context> base) {
// At the end of the chain. Return the base context to link to.
@@ -10981,17 +11019,21 @@
// Recursively copy the with and catch contexts.
HandleScope scope(isolate);
Handle<Context> previous(current->previous());
- Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
+ Handle<Context> new_previous =
+ CopyWithContextChain(isolate, function, previous, base);
Handle<Context> new_current;
if (current->IsCatchContext()) {
Handle<String> name(String::cast(current->extension()));
Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
new_current =
- isolate->factory()->NewCatchContext(new_previous, name, thrown_object);
+ isolate->factory()->NewCatchContext(function,
+ new_previous,
+ name,
+ thrown_object);
} else {
Handle<JSObject> extension(JSObject::cast(current->extension()));
new_current =
- isolate->factory()->NewWithContext(new_previous, extension);
+ isolate->factory()->NewWithContext(function, new_previous, extension);
}
return scope.CloseAndEscape(new_current);
}
@@ -11121,12 +11163,13 @@
context->set_extension(*local_scope);
// Copy any with contexts present and chain them in front of this context.
Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->fcontext());
- context = CopyWithContextChain(isolate, frame_context, context);
+ Handle<Context> function_context(frame_context->declaration_context());
+ context = CopyWithContextChain(isolate, go_between, frame_context, context);
if (additional_context->IsJSObject()) {
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
- context = isolate->factory()->NewWithContext(context, extension);
+ context =
+ isolate->factory()->NewWithContext(go_between, context, extension);
}
// Wrap the evaluation statement in a new function compiled in the newly