blob: 6738213f9b41e466d647495f7bb40a8c43fd68bf [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000050#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000055#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
kasperl@chromium.org71affb52009-05-26 05:44:31 +000058namespace v8 {
59namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
61
ager@chromium.org3e875802009-06-29 08:26:34 +000062#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65// Cast the given object to a value of the specified type and store
66// it in a variable with the given name. If the object is not of the
67// expected type call IllegalOperation and return.
68#define CONVERT_CHECKED(Type, name, obj) \
69 RUNTIME_ASSERT(obj->Is##Type()); \
70 Type* name = Type::cast(obj);
71
72#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
74 Handle<Type> name = args.at<Type>(index);
75
kasper.lundbd3ec4e2008-07-09 11:06:54 +000076// Cast the given object to a boolean and store it in a variable with
77// the given name. If the object is not a boolean call IllegalOperation
78// and return.
79#define CONVERT_BOOLEAN_CHECKED(name, obj) \
80 RUNTIME_ASSERT(obj->IsBoolean()); \
81 bool name = (obj)->IsTrue();
82
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000083// Cast the given object to a Smi and store its value in an int variable
84// with the given name. If the object is not a Smi call IllegalOperation
85// and return.
86#define CONVERT_SMI_CHECKED(name, obj) \
87 RUNTIME_ASSERT(obj->IsSmi()); \
88 int name = Smi::cast(obj)->value();
89
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090// Cast the given object to a double and store it in a variable with
91// the given name. If the object is not a number (as opposed to
92// the number not-a-number) call IllegalOperation and return.
93#define CONVERT_DOUBLE_CHECKED(name, obj) \
94 RUNTIME_ASSERT(obj->IsNumber()); \
95 double name = (obj)->Number();
96
97// Call the specified converter on the object *comand store the result in
98// a variable of the specified type with the given name. If the
99// object is not a Number call IllegalOperation and return.
100#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
101 RUNTIME_ASSERT(obj->IsNumber()); \
102 type name = NumberTo##Type(obj);
103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
106 JSObject* boilerplate) {
107 StackLimitCheck check(isolate);
108 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 if (!maybe_result->ToObject(&result)) return maybe_result;
114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 JSObject* copy = JSObject::cast(result);
116
117 // Deep copy local properties.
118 if (copy->HasFastProperties()) {
119 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 for (int i = 0; i < properties->length(); i++) {
121 Object* value = properties->get(i);
122 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 if (!maybe_result->ToObject(&result)) return maybe_result;
126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 }
129 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000130 int nof = copy->map()->inobject_properties();
131 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 Object* value = copy->InObjectPropertyAt(i);
133 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000134 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 }
140 }
141 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 if (!maybe_result->ToObject(&result)) return maybe_result;
145 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 FixedArray* names = FixedArray::cast(result);
147 copy->GetLocalPropertyNames(names, 0);
148 for (int i = 0; i < names->length(); i++) {
149 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 // Only deep copy fields from the object literal expression.
154 // In particular, don't try to copy the length attribute of
155 // an array.
156 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* value =
158 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 if (elements->map() == heap->fixed_cow_array_map()) {
180 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000181#ifdef DEBUG
182 for (int i = 0; i < elements->length(); i++) {
183 ASSERT(!elements->get(i)->IsJSObject());
184 }
185#endif
186 } else {
187 for (int i = 0; i < elements->length(); i++) {
188 Object* value = elements->get(i);
189 if (value->IsJSObject()) {
190 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
192 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 if (!maybe_result->ToObject(&result)) return maybe_result;
194 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000195 elements->set(i, result);
196 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000197 }
198 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 case JSObject::DICTIONARY_ELEMENTS: {
202 NumberDictionary* element_dictionary = copy->element_dictionary();
203 int capacity = element_dictionary->Capacity();
204 for (int i = 0; i < capacity; i++) {
205 Object* k = element_dictionary->KeyAt(i);
206 if (element_dictionary->IsKey(k)) {
207 Object* value = element_dictionary->ValueAt(i);
208 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
211 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000212 if (!maybe_result->ToObject(&result)) return maybe_result;
213 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000214 element_dictionary->ValueAtPut(i, result);
215 }
216 }
217 }
218 break;
219 }
220 default:
221 UNREACHABLE();
222 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000223 }
224 return copy;
225}
226
227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000228RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231}
232
233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000234RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000236 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237}
238
239
ager@chromium.org236ad962008-09-25 09:45:57 +0000240static Handle<Map> ComputeObjectLiteralMap(
241 Handle<Context> context,
242 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000243 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 int properties_length = constant_properties->length();
246 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 for (int p = 0; p != properties_length; p += 2) {
251 Object* key = constant_properties->get(p);
252 uint32_t element_index = 0;
253 if (key->IsSymbol()) {
254 number_of_symbol_keys++;
255 } else if (key->ToArrayIndex(&element_index)) {
256 // An index key does not require space in the property backing store.
257 number_of_properties--;
258 } else {
259 // Bail out as a non-symbol non-index key makes caching impossible.
260 // ASSERT to make sure that the if condition after the loop is false.
261 ASSERT(number_of_symbol_keys != number_of_properties);
262 break;
263 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 // If we only have symbols and array indices among keys then we can
266 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000268 if ((number_of_symbol_keys == number_of_properties) &&
269 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 Handle<FixedArray> keys =
272 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000273 if (number_of_symbol_keys > 0) {
274 int index = 0;
275 for (int p = 0; p < properties_length; p += 2) {
276 Object* key = constant_properties->get(p);
277 if (key->IsSymbol()) {
278 keys->set(index++, key);
279 }
280 }
281 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
286 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000287 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000289 Handle<Map>(context->object_function()->initial_map()),
290 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000291}
292
293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296 Handle<FixedArray> literals,
297 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299
300static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000303 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 bool should_have_fast_elements,
305 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306 // Get the global context from the literals array. This is the
307 // context in which the function was created and we use the object
308 // function from this context to create the object literal. We do
309 // not use the object function from the current global context
310 // because this might be the object function from another context
311 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 Handle<Context> context =
313 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 // In case we have function literals, we want the object to be in
316 // slow properties mode for now. We don't go in the map cache because
317 // maps with constant functions can't be shared if the functions are
318 // not the same (which is the common case).
319 bool is_result_from_cache = false;
320 Handle<Map> map = has_function_literal
321 ? Handle<Map>(context->object_function()->initial_map())
322 : ComputeObjectLiteralMap(context,
323 constant_properties,
324 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000327
328 // Normalize the elements of the boilerplate to save space if needed.
329 if (!should_have_fast_elements) NormalizeElements(boilerplate);
330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 // Add the constant properties to the boilerplate.
332 int length = constant_properties->length();
333 bool should_transform =
334 !is_result_from_cache && boilerplate->HasFastProperties();
335 if (should_transform || has_function_literal) {
336 // Normalize the properties of object to avoid n^2 behavior
337 // when extending the object multiple properties. Indicate the number of
338 // properties to be added.
339 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
340 }
341
342 for (int index = 0; index < length; index +=2) {
343 Handle<Object> key(constant_properties->get(index+0), isolate);
344 Handle<Object> value(constant_properties->get(index+1), isolate);
345 if (value->IsFixedArray()) {
346 // The value contains the constant_properties of a
347 // simple object or array literal.
348 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
349 value = CreateLiteralBoilerplate(isolate, literals, array);
350 if (value.is_null()) return value;
351 }
352 Handle<Object> result;
353 uint32_t element_index = 0;
354 if (key->IsSymbol()) {
355 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
356 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000357 result = SetOwnElement(boilerplate,
358 element_index,
359 value,
360 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<String> name(String::cast(*key));
363 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
365 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 } else if (key->ToArrayIndex(&element_index)) {
368 // Array index (uint32).
369 result = SetOwnElement(boilerplate,
370 element_index,
371 value,
372 kNonStrictMode);
373 } else {
374 // Non-uint32 number.
375 ASSERT(key->IsNumber());
376 double num = key->Number();
377 char arr[100];
378 Vector<char> buffer(arr, ARRAY_SIZE(arr));
379 const char* str = DoubleToCString(num, buffer);
380 Handle<String> name =
381 isolate->factory()->NewStringFromAscii(CStrVector(str));
382 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
383 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000385 // If setting the property on the boilerplate throws an
386 // exception, the exception is converted to an empty handle in
387 // the handle based operations. In that case, we need to
388 // convert back to an exception.
389 if (result.is_null()) return result;
390 }
391
392 // Transform to fast properties if necessary. For object literals with
393 // containing function literals we defer this operation until after all
394 // computed properties have been assigned so that we can generate
395 // constant function properties.
396 if (should_transform && !has_function_literal) {
397 TransformToFastProperties(boilerplate,
398 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
400
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000401 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000402}
403
404
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000405static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407 Handle<FixedArray> literals,
408 Handle<FixedArray> elements) {
409 // Create the JSArray.
410 Handle<JSFunction> constructor(
411 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 const bool is_cow =
415 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000416 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418
419 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420 if (is_cow) {
421#ifdef DEBUG
422 // Copy-on-write arrays must be shallow (and simple).
423 for (int i = 0; i < content->length(); i++) {
424 ASSERT(!content->get(i)->IsFixedArray());
425 }
426#endif
427 } else {
428 for (int i = 0; i < content->length(); i++) {
429 if (content->get(i)->IsFixedArray()) {
430 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000432 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
433 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (result.is_null()) return result;
436 content->set(i, *result);
437 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 }
439 }
440
441 // Set the elements.
442 Handle<JSArray>::cast(object)->SetContent(*content);
443 return object;
444}
445
446
447static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000449 Handle<FixedArray> literals,
450 Handle<FixedArray> array) {
451 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000454 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 return CreateObjectLiteralBoilerplate(isolate,
456 literals,
457 elements,
458 true,
459 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000460 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 return CreateObjectLiteralBoilerplate(isolate,
462 literals,
463 elements,
464 false,
465 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 default:
469 UNREACHABLE();
470 return Handle<Object>::null();
471 }
472}
473
474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000475RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000476 // Takes a FixedArray of elements containing the literal elements of
477 // the array literal and produces JSArray with those elements.
478 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000479 // which contains the context from which to get the Array function
480 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 ASSERT(args.length() == 3);
483 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
484 CONVERT_SMI_CHECKED(literals_index, args[1]);
485 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 Handle<Object> object =
488 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000489 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 // Update the functions literal and return the boilerplate.
492 literals->set(literals_index, *object);
493 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000497RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
501 CONVERT_SMI_CHECKED(literals_index, args[1]);
502 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 CONVERT_SMI_CHECKED(flags, args[3]);
504 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
505 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506
507 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 Handle<Object> boilerplate(literals->get(literals_index), isolate);
509 if (*boilerplate == isolate->heap()->undefined_value()) {
510 boilerplate = CreateObjectLiteralBoilerplate(isolate,
511 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000512 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 should_have_fast_elements,
514 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 if (boilerplate.is_null()) return Failure::Exception();
516 // Update the functions literal and return the boilerplate.
517 literals->set(literals_index, *boilerplate);
518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520}
521
522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000523RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000525 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
527 CONVERT_SMI_CHECKED(literals_index, args[1]);
528 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 CONVERT_SMI_CHECKED(flags, args[3]);
530 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
531 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000532
533 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 Handle<Object> boilerplate(literals->get(literals_index), isolate);
535 if (*boilerplate == isolate->heap()->undefined_value()) {
536 boilerplate = CreateObjectLiteralBoilerplate(isolate,
537 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000538 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 should_have_fast_elements,
540 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 if (boilerplate.is_null()) return Failure::Exception();
542 // Update the functions literal and return the boilerplate.
543 literals->set(literals_index, *boilerplate);
544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000551 ASSERT(args.length() == 3);
552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
553 CONVERT_SMI_CHECKED(literals_index, args[1]);
554 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
555
556 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 Handle<Object> boilerplate(literals->get(literals_index), isolate);
558 if (*boilerplate == isolate->heap()->undefined_value()) {
559 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 if (boilerplate.is_null()) return Failure::Exception();
561 // Update the functions literal and return the boilerplate.
562 literals->set(literals_index, *boilerplate);
563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565}
566
567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000568RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570 ASSERT(args.length() == 3);
571 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
572 CONVERT_SMI_CHECKED(literals_index, args[1]);
573 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
574
575 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 Handle<Object> boilerplate(literals->get(literals_index), isolate);
577 if (*boilerplate == isolate->heap()->undefined_value()) {
578 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579 if (boilerplate.is_null()) return Failure::Exception();
580 // Update the functions literal and return the boilerplate.
581 literals->set(literals_index, *boilerplate);
582 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000583 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000585 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588}
589
590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000591RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000592 ASSERT(args.length() == 2);
593 CONVERT_CHECKED(String, key, args[0]);
594 Object* value = args[1];
595 // Create a catch context extension object.
596 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 isolate->context()->global_context()->
598 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000599 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000601 if (!maybe_object->ToObject(&object)) return maybe_object;
602 }
ager@chromium.org32912102009-01-16 10:38:43 +0000603 // Assign the exception value to the catch variable and make sure
604 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000605 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000606 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
607 JSObject::cast(object)->SetProperty(
608 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000609 if (!maybe_value->ToObject(&value)) return maybe_value;
610 }
ager@chromium.org32912102009-01-16 10:38:43 +0000611 return object;
612}
613
614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 NoHandleAllocation ha;
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 return JSObject::cast(obj)->class_name();
621}
622
ager@chromium.org7c537e22008-10-16 08:43:32 +0000623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000624RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625 NoHandleAllocation ha;
626 ASSERT(args.length() == 2);
627 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
628 Object* O = args[0];
629 Object* V = args[1];
630 while (true) {
631 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 if (prototype->IsNull()) return isolate->heap()->false_value();
633 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 V = prototype;
635 }
636}
637
638
ager@chromium.org9085a012009-05-11 19:22:57 +0000639// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000640RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000641 NoHandleAllocation ha;
642 ASSERT(args.length() == 2);
643 CONVERT_CHECKED(JSObject, jsobject, args[0]);
644 CONVERT_CHECKED(JSObject, proto, args[1]);
645
646 // Sanity checks. The old prototype (that we are replacing) could
647 // theoretically be null, but if it is not null then check that we
648 // didn't already install a hidden prototype here.
649 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
650 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
651 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
652
653 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000654 Object* map_or_failure;
655 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
656 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
657 return maybe_map_or_failure;
658 }
659 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000660 Map* new_proto_map = Map::cast(map_or_failure);
661
lrn@chromium.org303ada72010-10-27 09:33:13 +0000662 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
663 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
664 return maybe_map_or_failure;
665 }
666 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000667 Map* new_map = Map::cast(map_or_failure);
668
669 // Set proto's prototype to be the old prototype of the object.
670 new_proto_map->set_prototype(jsobject->GetPrototype());
671 proto->set_map(new_proto_map);
672 new_proto_map->set_is_hidden_prototype();
673
674 // Set the object's prototype to proto.
675 new_map->set_prototype(proto);
676 jsobject->set_map(new_map);
677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000679}
680
681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000682RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000684 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000685 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000686 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687}
688
689
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000690// Recursively traverses hidden prototypes if property is not found
691static void GetOwnPropertyImplementation(JSObject* obj,
692 String* name,
693 LookupResult* result) {
694 obj->LocalLookupRealNamedProperty(name, result);
695
696 if (!result->IsProperty()) {
697 Object* proto = obj->GetPrototype();
698 if (proto->IsJSObject() &&
699 JSObject::cast(proto)->map()->is_hidden_prototype())
700 GetOwnPropertyImplementation(JSObject::cast(proto),
701 name, result);
702 }
703}
704
705
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000706static bool CheckAccessException(LookupResult* result,
707 v8::AccessType access_type) {
708 if (result->type() == CALLBACKS) {
709 Object* callback = result->GetCallbackObject();
710 if (callback->IsAccessorInfo()) {
711 AccessorInfo* info = AccessorInfo::cast(callback);
712 bool can_access =
713 (access_type == v8::ACCESS_HAS &&
714 (info->all_can_read() || info->all_can_write())) ||
715 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
716 (access_type == v8::ACCESS_SET && info->all_can_write());
717 return can_access;
718 }
719 }
720
721 return false;
722}
723
724
725static bool CheckAccess(JSObject* obj,
726 String* name,
727 LookupResult* result,
728 v8::AccessType access_type) {
729 ASSERT(result->IsProperty());
730
731 JSObject* holder = result->holder();
732 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000733 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000734 while (true) {
735 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000737 // Access check callback denied the access, but some properties
738 // can have a special permissions which override callbacks descision
739 // (currently see v8::AccessControl).
740 break;
741 }
742
743 if (current == holder) {
744 return true;
745 }
746
747 current = JSObject::cast(current->GetPrototype());
748 }
749
750 // API callbacks can have per callback access exceptions.
751 switch (result->type()) {
752 case CALLBACKS: {
753 if (CheckAccessException(result, access_type)) {
754 return true;
755 }
756 break;
757 }
758 case INTERCEPTOR: {
759 // If the object has an interceptor, try real named properties.
760 // Overwrite the result to fetch the correct property later.
761 holder->LookupRealNamedProperty(name, result);
762 if (result->IsProperty()) {
763 if (CheckAccessException(result, access_type)) {
764 return true;
765 }
766 }
767 break;
768 }
769 default:
770 break;
771 }
772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000773 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000774 return false;
775}
776
777
778// TODO(1095): we should traverse hidden prototype hierachy as well.
779static bool CheckElementAccess(JSObject* obj,
780 uint32_t index,
781 v8::AccessType access_type) {
782 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000783 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784 return false;
785 }
786
787 return true;
788}
789
790
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000791// Enumerator used as indices into the array returned from GetOwnProperty
792enum PropertyDescriptorIndices {
793 IS_ACCESSOR_INDEX,
794 VALUE_INDEX,
795 GETTER_INDEX,
796 SETTER_INDEX,
797 WRITABLE_INDEX,
798 ENUMERABLE_INDEX,
799 CONFIGURABLE_INDEX,
800 DESCRIPTOR_SIZE
801};
802
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000803// Returns an array with the property description:
804// if args[1] is not a property on args[0]
805// returns undefined
806// if args[1] is a data property on args[0]
807// [false, value, Writeable, Enumerable, Configurable]
808// if args[1] is an accessor on args[0]
809// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000810RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000811 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000812 Heap* heap = isolate->heap();
813 HandleScope scope(isolate);
814 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
815 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000816 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 CONVERT_ARG_CHECKED(JSObject, obj, 0);
818 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000819
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000820 // This could be an element.
821 uint32_t index;
822 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 switch (obj->HasLocalElement(index)) {
824 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000826
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000827 case JSObject::STRING_CHARACTER_ELEMENT: {
828 // Special handling of string objects according to ECMAScript 5
829 // 15.5.5.2. Note that this might be a string object with elements
830 // other than the actual string value. This is covered by the
831 // subsequent cases.
832 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
833 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000834 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000836 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000838 elms->set(WRITABLE_INDEX, heap->false_value());
839 elms->set(ENUMERABLE_INDEX, heap->false_value());
840 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 return *desc;
842 }
843
844 case JSObject::INTERCEPTED_ELEMENT:
845 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000846 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000847 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000849 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000850 elms->set(WRITABLE_INDEX, heap->true_value());
851 elms->set(ENUMERABLE_INDEX, heap->true_value());
852 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 return *desc;
854 }
855
856 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000857 Handle<JSObject> holder = obj;
858 if (obj->IsJSGlobalProxy()) {
859 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000861 ASSERT(proto->IsJSGlobalObject());
862 holder = Handle<JSObject>(JSObject::cast(proto));
863 }
864 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000865 int entry = dictionary->FindEntry(index);
866 ASSERT(entry != NumberDictionary::kNotFound);
867 PropertyDetails details = dictionary->DetailsAt(entry);
868 switch (details.type()) {
869 case CALLBACKS: {
870 // This is an accessor property with getter and/or setter.
871 FixedArray* callbacks =
872 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
875 elms->set(GETTER_INDEX, callbacks->get(0));
876 }
877 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
878 elms->set(SETTER_INDEX, callbacks->get(1));
879 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000880 break;
881 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000882 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000883 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000885 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000886 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000887 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000889 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000890 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000891 default:
892 UNREACHABLE();
893 break;
894 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
896 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000897 return *desc;
898 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000899 }
900 }
901
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000902 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000903 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000904
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000905 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000907 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000908
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000909 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000911 }
912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
914 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000915
916 bool is_js_accessor = (result.type() == CALLBACKS) &&
917 (result.GetCallbackObject()->IsFixedArray());
918
919 if (is_js_accessor) {
920 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922
923 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
924 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
925 elms->set(GETTER_INDEX, structure->get(0));
926 }
927 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
928 elms->set(SETTER_INDEX, structure->get(1));
929 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000930 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
932 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000933
934 PropertyAttributes attrs;
935 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000936 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000937 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
938 if (!maybe_value->ToObject(&value)) return maybe_value;
939 }
940 elms->set(VALUE_INDEX, value);
941 }
942
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000943 return *desc;
944}
945
946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000947RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000948 ASSERT(args.length() == 1);
949 CONVERT_CHECKED(JSObject, obj, args[0]);
950 return obj->PreventExtensions();
951}
952
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000954RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000955 ASSERT(args.length() == 1);
956 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000957 if (obj->IsJSGlobalProxy()) {
958 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000960 ASSERT(proto->IsJSGlobalObject());
961 obj = JSObject::cast(proto);
962 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 return obj->map()->is_extensible() ? isolate->heap()->true_value()
964 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000971 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
972 CONVERT_ARG_CHECKED(String, pattern, 1);
973 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000974 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
975 if (result.is_null()) return Failure::Exception();
976 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977}
978
979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000980RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000983 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985}
986
987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000988RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 ASSERT(args.length() == 1);
990 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000991 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993}
994
995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 ASSERT(args.length() == 2);
998 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001000 int index = field->value();
1001 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1002 InstanceType type = templ->map()->instance_type();
1003 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1004 type == OBJECT_TEMPLATE_INFO_TYPE);
1005 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001006 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001007 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1008 } else {
1009 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1010 }
1011 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012}
1013
1014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001015RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001016 ASSERT(args.length() == 1);
1017 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001018 Map* old_map = object->map();
1019 bool needs_access_checks = old_map->is_access_check_needed();
1020 if (needs_access_checks) {
1021 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001022 Object* new_map;
1023 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1024 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1025 }
ager@chromium.org32912102009-01-16 10:38:43 +00001026
1027 Map::cast(new_map)->set_is_access_check_needed(false);
1028 object->set_map(Map::cast(new_map));
1029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 return needs_access_checks ? isolate->heap()->true_value()
1031 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001038 Map* old_map = object->map();
1039 if (!old_map->is_access_check_needed()) {
1040 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001041 Object* new_map;
1042 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1043 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1044 }
ager@chromium.org32912102009-01-16 10:38:43 +00001045
1046 Map::cast(new_map)->set_is_access_check_needed(true);
1047 object->set_map(Map::cast(new_map));
1048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001050}
1051
1052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001053static Failure* ThrowRedeclarationError(Isolate* isolate,
1054 const char* type,
1055 Handle<String> name) {
1056 HandleScope scope(isolate);
1057 Handle<Object> type_handle =
1058 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 Handle<Object> args[2] = { type_handle, name };
1060 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1062 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063}
1064
1065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001066RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001067 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
1069 Handle<GlobalObject> global = Handle<GlobalObject>(
1070 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071
ager@chromium.org3811b432009-10-28 14:53:37 +00001072 Handle<Context> context = args.at<Context>(0);
1073 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 StrictModeFlag strict_mode =
1076 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1077 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078
1079 // Compute the property attributes. According to ECMA-262, section
1080 // 13, page 71, the property must be read-only and
1081 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1082 // property as read-only, so we don't either.
1083 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 // Traverse the name/value pairs and set the properties.
1086 int length = pairs->length();
1087 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
1092 // We have to declare a global const property. To capture we only
1093 // assign to it when evaluating the assignment for "const x =
1094 // <expr>" the initial value is the hole.
1095 bool is_const_property = value->IsTheHole();
1096
1097 if (value->IsUndefined() || is_const_property) {
1098 // Lookup the property in the global object, and don't set the
1099 // value of the variable if the property is already there.
1100 LookupResult lookup;
1101 global->Lookup(*name, &lookup);
1102 if (lookup.IsProperty()) {
1103 // Determine if the property is local by comparing the holder
1104 // against the global object. The information will be used to
1105 // avoid throwing re-declaration errors when declaring
1106 // variables or constants that exist in the prototype chain.
1107 bool is_local = (*global == lookup.holder());
1108 // Get the property attributes and determine if the property is
1109 // read-only.
1110 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1111 bool is_read_only = (attributes & READ_ONLY) != 0;
1112 if (lookup.type() == INTERCEPTOR) {
1113 // If the interceptor says the property is there, we
1114 // just return undefined without overwriting the property.
1115 // Otherwise, we continue to setting the property.
1116 if (attributes != ABSENT) {
1117 // Check if the existing property conflicts with regards to const.
1118 if (is_local && (is_read_only || is_const_property)) {
1119 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121 };
1122 // The property already exists without conflicting: Go to
1123 // the next declaration.
1124 continue;
1125 }
1126 // Fall-through and introduce the absent property by using
1127 // SetProperty.
1128 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001129 // For const properties, we treat a callback with this name
1130 // even in the prototype as a conflicting declaration.
1131 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001133 }
1134 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 if (is_local && (is_read_only || is_const_property)) {
1136 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 }
1139 // The property already exists without conflicting: Go to
1140 // the next declaration.
1141 continue;
1142 }
1143 }
1144 } else {
1145 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001146 Handle<SharedFunctionInfo> shared =
1147 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001149 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1150 context,
1151 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 value = function;
1153 }
1154
1155 LookupResult lookup;
1156 global->LocalLookup(*name, &lookup);
1157
1158 PropertyAttributes attributes = is_const_property
1159 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1160 : base;
1161
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001162 // There's a local property that we need to overwrite because
1163 // we're either declaring a function or there's an interceptor
1164 // that claims the property is absent.
1165 //
1166 // Check for conflicting re-declarations. We cannot have
1167 // conflicting types in case of intercepted properties because
1168 // they are absent.
1169 if (lookup.IsProperty() &&
1170 (lookup.type() != INTERCEPTOR) &&
1171 (lookup.IsReadOnly() || is_const_property)) {
1172 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001176 // Safari does not allow the invocation of callback setters for
1177 // function declarations. To mimic this behavior, we do not allow
1178 // the invocation of setters for function values. This makes a
1179 // difference for global functions with the same names as event
1180 // handlers such as "function onload() {}". Firefox does call the
1181 // onload setter in those case and Safari does not. We follow
1182 // Safari for compatibility.
1183 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001184 // Do not change DONT_DELETE to false from true.
1185 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1186 attributes = static_cast<PropertyAttributes>(
1187 attributes | (lookup.GetAttributes() & DONT_DELETE));
1188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 RETURN_IF_EMPTY_HANDLE(isolate,
1190 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001191 name,
1192 value,
1193 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001195 RETURN_IF_EMPTY_HANDLE(isolate,
1196 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001197 name,
1198 value,
1199 attributes,
1200 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201 }
1202 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 ASSERT(!isolate->has_pending_exception());
1205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206}
1207
1208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001209RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001210 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001211 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212
ager@chromium.org7c537e22008-10-16 08:43:32 +00001213 CONVERT_ARG_CHECKED(Context, context, 0);
1214 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001217 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219
1220 // Declarations are always done in the function context.
1221 context = Handle<Context>(context->fcontext());
1222
1223 int index;
1224 PropertyAttributes attributes;
1225 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001226 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227 context->Lookup(name, flags, &index, &attributes);
1228
1229 if (attributes != ABSENT) {
1230 // The name was declared before; check for conflicting
1231 // re-declarations: This is similar to the code in parser.cc in
1232 // the AstBuildingParser::Declare function.
1233 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1234 // Functions are not read-only.
1235 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1236 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238 }
1239
1240 // Initialize it if necessary.
1241 if (*initial_value != NULL) {
1242 if (index >= 0) {
1243 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001244 // the function context or the arguments object.
1245 if (holder->IsContext()) {
1246 ASSERT(holder.is_identical_to(context));
1247 if (((attributes & READ_ONLY) == 0) ||
1248 context->get(index)->IsTheHole()) {
1249 context->set(index, *initial_value);
1250 }
1251 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001252 // The holder is an arguments object.
1253 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001254 Handle<Object> result = SetElement(arguments, index, initial_value,
1255 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001256 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258 } else {
1259 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001260 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001261 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001263 SetProperty(context_ext, name, initial_value,
1264 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 }
1266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001269 // The property is not in the function context. It needs to be
1270 // "declared" in the function context's extension context, or in the
1271 // global context.
1272 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001273 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001274 // The function context's extension context exists - use it.
1275 context_ext = Handle<JSObject>(context->extension());
1276 } else {
1277 // The function context's extension context does not exists - allocate
1278 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 context_ext = isolate->factory()->NewJSObject(
1280 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001281 // And store it in the extension slot.
1282 context->set_extension(*context_ext);
1283 }
1284 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285
ager@chromium.org7c537e22008-10-16 08:43:32 +00001286 // Declare the property by setting it to the initial value if provided,
1287 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1288 // constant declarations).
1289 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001291 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001292 // Declaring a const context slot is a conflicting declaration if
1293 // there is a callback with that name in a prototype. It is
1294 // allowed to introduce const variables in
1295 // JSContextExtensionObjects. They are treated specially in
1296 // SetProperty and no setters are invoked for those since they are
1297 // not real JSObjects.
1298 if (initial_value->IsTheHole() &&
1299 !context_ext->IsJSContextExtensionObject()) {
1300 LookupResult lookup;
1301 context_ext->Lookup(*name, &lookup);
1302 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001304 }
1305 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001306 RETURN_IF_EMPTY_HANDLE(isolate,
1307 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001308 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 }
1310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312}
1313
1314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001315RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001317 // args[0] == name
1318 // args[1] == strict_mode
1319 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320
1321 // Determine if we need to assign to the variable if it already
1322 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001323 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1324 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
1326 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001327 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 RUNTIME_ASSERT(args[1]->IsSmi());
1329 StrictModeFlag strict_mode =
1330 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1331 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332
1333 // According to ECMA-262, section 12.2, page 62, the property must
1334 // not be deletable.
1335 PropertyAttributes attributes = DONT_DELETE;
1336
1337 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001338 // there, there is a property with this name in the prototype chain.
1339 // We follow Safari and Firefox behavior and only set the property
1340 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001341 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001342 // Note that objects can have hidden prototypes, so we need to traverse
1343 // the whole chain of hidden prototypes to do a 'local' lookup.
1344 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001346 while (true) {
1347 real_holder->LocalLookup(*name, &lookup);
1348 if (lookup.IsProperty()) {
1349 // Determine if this is a redeclaration of something read-only.
1350 if (lookup.IsReadOnly()) {
1351 // If we found readonly property on one of hidden prototypes,
1352 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 if (real_holder != isolate->context()->global()) break;
1354 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001355 }
1356
1357 // Determine if this is a redeclaration of an intercepted read-only
1358 // property and figure out if the property exists at all.
1359 bool found = true;
1360 PropertyType type = lookup.type();
1361 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001363 Handle<JSObject> holder(real_holder);
1364 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1365 real_holder = *holder;
1366 if (intercepted == ABSENT) {
1367 // The interceptor claims the property isn't there. We need to
1368 // make sure to introduce it.
1369 found = false;
1370 } else if ((intercepted & READ_ONLY) != 0) {
1371 // The property is present, but read-only. Since we're trying to
1372 // overwrite it with a variable declaration we must throw a
1373 // re-declaration error. However if we found readonly property
1374 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 if (real_holder != isolate->context()->global()) break;
1376 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001377 }
1378 }
1379
1380 if (found && !assign) {
1381 // The global property is there and we're not assigning any value
1382 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 }
1385
1386 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001388 return real_holder->SetProperty(
1389 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001390 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001391
1392 Object* proto = real_holder->GetPrototype();
1393 if (!proto->IsJSObject())
1394 break;
1395
1396 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1397 break;
1398
1399 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403 if (assign) {
1404 return global->SetProperty(*name, args[2], attributes, strict_mode);
1405 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407}
1408
1409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001410RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 // All constants are declared with an initial value. The name
1412 // of the constant is the first argument and the initial value
1413 // is the second.
1414 RUNTIME_ASSERT(args.length() == 2);
1415 CONVERT_ARG_CHECKED(String, name, 0);
1416 Handle<Object> value = args.at<Object>(1);
1417
1418 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
1421 // According to ECMA-262, section 12.2, page 62, the property must
1422 // not be deletable. Since it's a const, it must be READ_ONLY too.
1423 PropertyAttributes attributes =
1424 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1425
1426 // Lookup the property locally in the global object. If it isn't
1427 // there, we add the property and take special precautions to always
1428 // add it as a local property even in case of callbacks in the
1429 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001430 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 LookupResult lookup;
1432 global->LocalLookup(*name, &lookup);
1433 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001434 return global->SetLocalPropertyIgnoreAttributes(*name,
1435 *value,
1436 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437 }
1438
1439 // Determine if this is a redeclaration of something not
1440 // read-only. In case the result is hidden behind an interceptor we
1441 // need to ask it for the property attributes.
1442 if (!lookup.IsReadOnly()) {
1443 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445 }
1446
1447 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1448
1449 // Throw re-declaration error if the intercepted property is present
1450 // but not read-only.
1451 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 }
1454
1455 // Restore global object from context (in case of GC) and continue
1456 // with setting the value because the property is either absent or
1457 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 HandleScope handle_scope(isolate);
1459 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001461 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462 // property through an interceptor and only do it if it's
1463 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 RETURN_IF_EMPTY_HANDLE(isolate,
1466 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467 name,
1468 value,
1469 attributes,
1470 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 return *value;
1472 }
1473
1474 // Set the value, but only we're assigning the initial value to a
1475 // constant. For now, we determine this by checking if the
1476 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478 PropertyType type = lookup.type();
1479 if (type == FIELD) {
1480 FixedArray* properties = global->properties();
1481 int index = lookup.GetFieldIndex();
1482 if (properties->get(index)->IsTheHole()) {
1483 properties->set(index, *value);
1484 }
1485 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001486 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1487 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 }
1489 } else {
1490 // Ignore re-initialization of constants that have already been
1491 // assigned a function value.
1492 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1493 }
1494
1495 // Use the set value as the result of the operation.
1496 return *value;
1497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001501 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 ASSERT(args.length() == 3);
1503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001504 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505 ASSERT(!value->IsTheHole());
1506 CONVERT_ARG_CHECKED(Context, context, 1);
1507 Handle<String> name(String::cast(args[2]));
1508
1509 // Initializations are always done in the function context.
1510 context = Handle<Context>(context->fcontext());
1511
1512 int index;
1513 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001514 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001515 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 context->Lookup(name, flags, &index, &attributes);
1517
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001518 // In most situations, the property introduced by the const
1519 // declaration should be present in the context extension object.
1520 // However, because declaration and initialization are separate, the
1521 // property might have been deleted (if it was introduced by eval)
1522 // before we reach the initialization point.
1523 //
1524 // Example:
1525 //
1526 // function f() { eval("delete x; const x;"); }
1527 //
1528 // In that case, the initialization behaves like a normal assignment
1529 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 // Property was found in a context.
1532 if (holder->IsContext()) {
1533 // The holder cannot be the function context. If it is, there
1534 // should have been a const redeclaration error when declaring
1535 // the const property.
1536 ASSERT(!holder.is_identical_to(context));
1537 if ((attributes & READ_ONLY) == 0) {
1538 Handle<Context>::cast(holder)->set(index, *value);
1539 }
1540 } else {
1541 // The holder is an arguments object.
1542 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001543 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001544 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001546 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 }
1548 return *value;
1549 }
1550
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001551 // The property could not be found, we introduce it in the global
1552 // context.
1553 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554 Handle<JSObject> global = Handle<JSObject>(
1555 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001556 // Strict mode not needed (const disallowed in strict mode).
1557 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001560 return *value;
1561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 // The property was present in a context extension object.
1564 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001566 if (*context_ext == context->extension()) {
1567 // This is the property that was introduced by the const
1568 // declaration. Set it if it hasn't been set before. NOTE: We
1569 // cannot use GetProperty() to get the current value as it
1570 // 'unholes' the value.
1571 LookupResult lookup;
1572 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1573 ASSERT(lookup.IsProperty()); // the property was declared
1574 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1575
1576 PropertyType type = lookup.type();
1577 if (type == FIELD) {
1578 FixedArray* properties = context_ext->properties();
1579 int index = lookup.GetFieldIndex();
1580 if (properties->get(index)->IsTheHole()) {
1581 properties->set(index, *value);
1582 }
1583 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001584 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1585 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001586 }
1587 } else {
1588 // We should not reach here. Any real, named property should be
1589 // either a field or a dictionary slot.
1590 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 }
1592 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001593 // The property was found in a different context extension object.
1594 // Set it if it is not a read-only property.
1595 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001596 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001597 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001599 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 return *value;
1604}
1605
1606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001607RUNTIME_FUNCTION(MaybeObject*,
1608 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001609 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001610 ASSERT(args.length() == 2);
1611 CONVERT_ARG_CHECKED(JSObject, object, 0);
1612 CONVERT_SMI_CHECKED(properties, args[1]);
1613 if (object->HasFastProperties()) {
1614 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1615 }
1616 return *object;
1617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001621 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001622 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001623 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1624 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001625 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001626 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001627 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001628 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001629 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001630 RUNTIME_ASSERT(index >= 0);
1631 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001633 Handle<Object> result = RegExpImpl::Exec(regexp,
1634 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001635 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001636 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001637 if (result.is_null()) return Failure::Exception();
1638 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639}
1640
1641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001642RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001643 ASSERT(args.length() == 3);
1644 CONVERT_SMI_CHECKED(elements_count, args[0]);
1645 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001646 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001647 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001648 Object* new_object;
1649 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001650 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1652 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001653 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1655 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001656 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1657 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001658 {
1659 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001660 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001661 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001662 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001663 }
1664 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 array->set_elements(elements);
1667 array->set_length(Smi::FromInt(elements_count));
1668 // Write in-object properties after the length of the array.
1669 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1670 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1671 return array;
1672}
1673
1674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001675RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001676 AssertNoAllocation no_alloc;
1677 ASSERT(args.length() == 5);
1678 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1679 CONVERT_CHECKED(String, source, args[1]);
1680
1681 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001683
1684 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001685 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001686
1687 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001689
1690 Map* map = regexp->map();
1691 Object* constructor = map->constructor();
1692 if (constructor->IsJSFunction() &&
1693 JSFunction::cast(constructor)->initial_map() == map) {
1694 // If we still have the original map, set in-object properties directly.
1695 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1696 // TODO(lrn): Consider skipping write barrier on booleans as well.
1697 // Both true and false should be in oldspace at all times.
1698 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1701 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1702 Smi::FromInt(0),
1703 SKIP_WRITE_BARRIER);
1704 return regexp;
1705 }
1706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001708 PropertyAttributes final =
1709 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1710 PropertyAttributes writable =
1711 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001713 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001714 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001715 source,
1716 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001717 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001719 global,
1720 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001721 ASSERT(!result->IsFailure());
1722 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001724 ignoreCase,
1725 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001728 multiline,
1729 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 ASSERT(!result->IsFailure());
1731 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001733 Smi::FromInt(0),
1734 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 ASSERT(!result->IsFailure());
1736 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001737 return regexp;
1738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001743 ASSERT(args.length() == 1);
1744 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1745 // This is necessary to enable fast checks for absence of elements
1746 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001748 return Smi::FromInt(0);
1749}
1750
1751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1753 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001754 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001755 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1757 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1758 Handle<JSFunction> optimized =
1759 isolate->factory()->NewFunction(key,
1760 JS_OBJECT_TYPE,
1761 JSObject::kHeaderSize,
1762 code,
1763 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001764 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001765 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001766 return optimized;
1767}
1768
1769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001770RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001772 ASSERT(args.length() == 1);
1773 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1774
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001775 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1776 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1777 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1778 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1779 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1780 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1781 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001782
1783 return *holder;
1784}
1785
1786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001788 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 Context* global_context =
1790 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001791 return global_context->global()->global_receiver();
1792}
1793
1794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001795RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 ASSERT(args.length() == 4);
1798 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1799 int index = Smi::cast(args[1])->value();
1800 Handle<String> pattern = args.at<String>(2);
1801 Handle<String> flags = args.at<String>(3);
1802
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001803 // Get the RegExp function from the context in the literals array.
1804 // This is the RegExp function from the context in which the
1805 // function was created. We do not use the RegExp function from the
1806 // current global context because this might be the RegExp function
1807 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001808 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001809 Handle<JSFunction>(
1810 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811 // Compute the regular expression literal.
1812 bool has_pending_exception;
1813 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001814 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1815 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818 return Failure::Exception();
1819 }
1820 literals->set(index, *regexp);
1821 return *regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 NoHandleAllocation ha;
1827 ASSERT(args.length() == 1);
1828
1829 CONVERT_CHECKED(JSFunction, f, args[0]);
1830 return f->shared()->name();
1831}
1832
1833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001834RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001835 NoHandleAllocation ha;
1836 ASSERT(args.length() == 2);
1837
1838 CONVERT_CHECKED(JSFunction, f, args[0]);
1839 CONVERT_CHECKED(String, name, args[1]);
1840 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 1);
1848
1849 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 Object* obj = f->RemovePrototype();
1851 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001854}
1855
1856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 ASSERT(args.length() == 1);
1860
1861 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1863 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864
1865 return *GetScriptWrapper(Handle<Script>::cast(script));
1866}
1867
1868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 NoHandleAllocation ha;
1871 ASSERT(args.length() == 1);
1872
1873 CONVERT_CHECKED(JSFunction, f, args[0]);
1874 return f->shared()->GetSourceCode();
1875}
1876
1877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001879 NoHandleAllocation ha;
1880 ASSERT(args.length() == 1);
1881
1882 CONVERT_CHECKED(JSFunction, fun, args[0]);
1883 int pos = fun->shared()->start_position();
1884 return Smi::FromInt(pos);
1885}
1886
1887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001889 ASSERT(args.length() == 2);
1890
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001891 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001892 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1893
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001894 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1895
1896 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001897 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001902 NoHandleAllocation ha;
1903 ASSERT(args.length() == 2);
1904
1905 CONVERT_CHECKED(JSFunction, fun, args[0]);
1906 CONVERT_CHECKED(String, name, args[1]);
1907 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001908 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909}
1910
1911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001912RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 NoHandleAllocation ha;
1914 ASSERT(args.length() == 2);
1915
1916 CONVERT_CHECKED(JSFunction, fun, args[0]);
1917 CONVERT_CHECKED(Smi, length, args[1]);
1918 fun->shared()->set_length(length->value());
1919 return length;
1920}
1921
1922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001923RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 ASSERT(args.length() == 2);
1926
1927 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001928 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001929 Object* obj;
1930 { MaybeObject* maybe_obj =
1931 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1932 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 return args[0]; // return TOS
1935}
1936
1937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941
1942 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001943 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1944 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001945}
1946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
1952 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001953 return f->IsBuiltin() ? isolate->heap()->true_value() :
1954 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001955}
1956
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001958RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 ASSERT(args.length() == 2);
1961
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001962 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963 Handle<Object> code = args.at<Object>(1);
1964
1965 Handle<Context> context(target->context());
1966
1967 if (!code->IsNull()) {
1968 RUNTIME_ASSERT(code->IsJSFunction());
1969 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001971
1972 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 return Failure::Exception();
1974 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975 // Since we don't store the source for this we should never
1976 // optimize this.
1977 shared->code()->set_optimizable(false);
1978
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001979 // Set the code, scope info, formal parameter count,
1980 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001981 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001982 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001983 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001986 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001987 // Set the source code of the target function to undefined.
1988 // SetCode is only used for built-in constructors like String,
1989 // Array, and Object, and some web code
1990 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001992 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001993 // Clear the optimization hints related to the compiled code as these are no
1994 // longer valid when the code is overwritten.
1995 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 context = Handle<Context>(fun->context());
1997
1998 // Make sure we get a fresh copy of the literal vector to avoid
1999 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002000 int number_of_literals = fun->NumberOfLiterals();
2001 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002004 // Insert the object, regexp and array functions in the literals
2005 // array prefix. These are the functions that will be used when
2006 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002007 literals->set(JSFunction::kLiteralGlobalContextIndex,
2008 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 // It's okay to skip the write barrier here because the literals
2011 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002012 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002013 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 }
2015
2016 target->set_context(*context);
2017 return *target;
2018}
2019
2020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002021RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002022 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002023 ASSERT(args.length() == 2);
2024 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2025 CONVERT_SMI_CHECKED(num, args[1]);
2026 RUNTIME_ASSERT(num >= 0);
2027 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002028 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002029}
2030
2031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002032MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2033 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002034 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002035 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002036 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002037 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002038 }
2039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002040 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002041}
2042
2043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002044RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 NoHandleAllocation ha;
2046 ASSERT(args.length() == 2);
2047
2048 CONVERT_CHECKED(String, subject, args[0]);
2049 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002050 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002052 uint32_t i = 0;
2053 if (index->IsSmi()) {
2054 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002056 i = value;
2057 } else {
2058 ASSERT(index->IsHeapNumber());
2059 double value = HeapNumber::cast(index)->value();
2060 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002061 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002062
2063 // Flatten the string. If someone wants to get a char at an index
2064 // in a cons string, it is likely that more indices will be
2065 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002066 Object* flat;
2067 { MaybeObject* maybe_flat = subject->TryFlatten();
2068 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2069 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002070 subject = String::cast(flat);
2071
2072 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002074 }
2075
2076 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002077}
2078
2079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002081 NoHandleAllocation ha;
2082 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002083 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084}
2085
lrn@chromium.org25156de2010-04-06 13:10:27 +00002086
2087class FixedArrayBuilder {
2088 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002089 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2090 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002091 length_(0) {
2092 // Require a non-zero initial size. Ensures that doubling the size to
2093 // extend the array will work.
2094 ASSERT(initial_capacity > 0);
2095 }
2096
2097 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2098 : array_(backing_store),
2099 length_(0) {
2100 // Require a non-zero initial size. Ensures that doubling the size to
2101 // extend the array will work.
2102 ASSERT(backing_store->length() > 0);
2103 }
2104
2105 bool HasCapacity(int elements) {
2106 int length = array_->length();
2107 int required_length = length_ + elements;
2108 return (length >= required_length);
2109 }
2110
2111 void EnsureCapacity(int elements) {
2112 int length = array_->length();
2113 int required_length = length_ + elements;
2114 if (length < required_length) {
2115 int new_length = length;
2116 do {
2117 new_length *= 2;
2118 } while (new_length < required_length);
2119 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002120 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002121 array_->CopyTo(0, *extended_array, 0, length_);
2122 array_ = extended_array;
2123 }
2124 }
2125
2126 void Add(Object* value) {
2127 ASSERT(length_ < capacity());
2128 array_->set(length_, value);
2129 length_++;
2130 }
2131
2132 void Add(Smi* value) {
2133 ASSERT(length_ < capacity());
2134 array_->set(length_, value);
2135 length_++;
2136 }
2137
2138 Handle<FixedArray> array() {
2139 return array_;
2140 }
2141
2142 int length() {
2143 return length_;
2144 }
2145
2146 int capacity() {
2147 return array_->length();
2148 }
2149
2150 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002151 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002152 result_array->set_length(Smi::FromInt(length_));
2153 return result_array;
2154 }
2155
2156 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2157 target_array->set_elements(*array_);
2158 target_array->set_length(Smi::FromInt(length_));
2159 return target_array;
2160 }
2161
2162 private:
2163 Handle<FixedArray> array_;
2164 int length_;
2165};
2166
2167
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002168// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002169const int kStringBuilderConcatHelperLengthBits = 11;
2170const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002171
2172template <typename schar>
2173static inline void StringBuilderConcatHelper(String*,
2174 schar*,
2175 FixedArray*,
2176 int);
2177
lrn@chromium.org25156de2010-04-06 13:10:27 +00002178typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2179 StringBuilderSubstringLength;
2180typedef BitField<int,
2181 kStringBuilderConcatHelperLengthBits,
2182 kStringBuilderConcatHelperPositionBits>
2183 StringBuilderSubstringPosition;
2184
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002185
2186class ReplacementStringBuilder {
2187 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 ReplacementStringBuilder(Heap* heap,
2189 Handle<String> subject,
2190 int estimated_part_count)
2191 : heap_(heap),
2192 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002193 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002194 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002195 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196 // Require a non-zero initial size. Ensures that doubling the size to
2197 // extend the array will work.
2198 ASSERT(estimated_part_count > 0);
2199 }
2200
lrn@chromium.org25156de2010-04-06 13:10:27 +00002201 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2202 int from,
2203 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002204 ASSERT(from >= 0);
2205 int length = to - from;
2206 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 if (StringBuilderSubstringLength::is_valid(length) &&
2208 StringBuilderSubstringPosition::is_valid(from)) {
2209 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2210 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002211 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002212 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002213 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002214 builder->Add(Smi::FromInt(-length));
2215 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002216 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002217 }
2218
2219
2220 void EnsureCapacity(int elements) {
2221 array_builder_.EnsureCapacity(elements);
2222 }
2223
2224
2225 void AddSubjectSlice(int from, int to) {
2226 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002228 }
2229
2230
2231 void AddString(Handle<String> string) {
2232 int length = string->length();
2233 ASSERT(length > 0);
2234 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002235 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002236 is_ascii_ = false;
2237 }
2238 IncrementCharacterCount(length);
2239 }
2240
2241
2242 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002243 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002245 }
2246
2247 Handle<String> joined_string;
2248 if (is_ascii_) {
2249 joined_string = NewRawAsciiString(character_count_);
2250 AssertNoAllocation no_alloc;
2251 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2252 char* char_buffer = seq->GetChars();
2253 StringBuilderConcatHelper(*subject_,
2254 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002255 *array_builder_.array(),
2256 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002257 } else {
2258 // Non-ASCII.
2259 joined_string = NewRawTwoByteString(character_count_);
2260 AssertNoAllocation no_alloc;
2261 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2262 uc16* char_buffer = seq->GetChars();
2263 StringBuilderConcatHelper(*subject_,
2264 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002265 *array_builder_.array(),
2266 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 }
2268 return joined_string;
2269 }
2270
2271
2272 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002273 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002274 V8::FatalProcessOutOfMemory("String.replace result too large.");
2275 }
2276 character_count_ += by;
2277 }
2278
lrn@chromium.org25156de2010-04-06 13:10:27 +00002279 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002280 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002281 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002284 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 CALL_HEAP_FUNCTION(heap_->isolate(),
2286 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 }
2288
2289
2290 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002291 CALL_HEAP_FUNCTION(heap_->isolate(),
2292 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002293 }
2294
2295
2296 void AddElement(Object* element) {
2297 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002298 ASSERT(array_builder_.capacity() > array_builder_.length());
2299 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002302 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002303 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002305 int character_count_;
2306 bool is_ascii_;
2307};
2308
2309
2310class CompiledReplacement {
2311 public:
2312 CompiledReplacement()
2313 : parts_(1), replacement_substrings_(0) {}
2314
2315 void Compile(Handle<String> replacement,
2316 int capture_count,
2317 int subject_length);
2318
2319 void Apply(ReplacementStringBuilder* builder,
2320 int match_from,
2321 int match_to,
2322 Handle<JSArray> last_match_info);
2323
2324 // Number of distinct parts of the replacement pattern.
2325 int parts() {
2326 return parts_.length();
2327 }
2328 private:
2329 enum PartType {
2330 SUBJECT_PREFIX = 1,
2331 SUBJECT_SUFFIX,
2332 SUBJECT_CAPTURE,
2333 REPLACEMENT_SUBSTRING,
2334 REPLACEMENT_STRING,
2335
2336 NUMBER_OF_PART_TYPES
2337 };
2338
2339 struct ReplacementPart {
2340 static inline ReplacementPart SubjectMatch() {
2341 return ReplacementPart(SUBJECT_CAPTURE, 0);
2342 }
2343 static inline ReplacementPart SubjectCapture(int capture_index) {
2344 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2345 }
2346 static inline ReplacementPart SubjectPrefix() {
2347 return ReplacementPart(SUBJECT_PREFIX, 0);
2348 }
2349 static inline ReplacementPart SubjectSuffix(int subject_length) {
2350 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2351 }
2352 static inline ReplacementPart ReplacementString() {
2353 return ReplacementPart(REPLACEMENT_STRING, 0);
2354 }
2355 static inline ReplacementPart ReplacementSubString(int from, int to) {
2356 ASSERT(from >= 0);
2357 ASSERT(to > from);
2358 return ReplacementPart(-from, to);
2359 }
2360
2361 // If tag <= 0 then it is the negation of a start index of a substring of
2362 // the replacement pattern, otherwise it's a value from PartType.
2363 ReplacementPart(int tag, int data)
2364 : tag(tag), data(data) {
2365 // Must be non-positive or a PartType value.
2366 ASSERT(tag < NUMBER_OF_PART_TYPES);
2367 }
2368 // Either a value of PartType or a non-positive number that is
2369 // the negation of an index into the replacement string.
2370 int tag;
2371 // The data value's interpretation depends on the value of tag:
2372 // tag == SUBJECT_PREFIX ||
2373 // tag == SUBJECT_SUFFIX: data is unused.
2374 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2375 // tag == REPLACEMENT_SUBSTRING ||
2376 // tag == REPLACEMENT_STRING: data is index into array of substrings
2377 // of the replacement string.
2378 // tag <= 0: Temporary representation of the substring of the replacement
2379 // string ranging over -tag .. data.
2380 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2381 // substring objects.
2382 int data;
2383 };
2384
2385 template<typename Char>
2386 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2387 Vector<Char> characters,
2388 int capture_count,
2389 int subject_length) {
2390 int length = characters.length();
2391 int last = 0;
2392 for (int i = 0; i < length; i++) {
2393 Char c = characters[i];
2394 if (c == '$') {
2395 int next_index = i + 1;
2396 if (next_index == length) { // No next character!
2397 break;
2398 }
2399 Char c2 = characters[next_index];
2400 switch (c2) {
2401 case '$':
2402 if (i > last) {
2403 // There is a substring before. Include the first "$".
2404 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2405 last = next_index + 1; // Continue after the second "$".
2406 } else {
2407 // Let the next substring start with the second "$".
2408 last = next_index;
2409 }
2410 i = next_index;
2411 break;
2412 case '`':
2413 if (i > last) {
2414 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2415 }
2416 parts->Add(ReplacementPart::SubjectPrefix());
2417 i = next_index;
2418 last = i + 1;
2419 break;
2420 case '\'':
2421 if (i > last) {
2422 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2423 }
2424 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2425 i = next_index;
2426 last = i + 1;
2427 break;
2428 case '&':
2429 if (i > last) {
2430 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2431 }
2432 parts->Add(ReplacementPart::SubjectMatch());
2433 i = next_index;
2434 last = i + 1;
2435 break;
2436 case '0':
2437 case '1':
2438 case '2':
2439 case '3':
2440 case '4':
2441 case '5':
2442 case '6':
2443 case '7':
2444 case '8':
2445 case '9': {
2446 int capture_ref = c2 - '0';
2447 if (capture_ref > capture_count) {
2448 i = next_index;
2449 continue;
2450 }
2451 int second_digit_index = next_index + 1;
2452 if (second_digit_index < length) {
2453 // Peek ahead to see if we have two digits.
2454 Char c3 = characters[second_digit_index];
2455 if ('0' <= c3 && c3 <= '9') { // Double digits.
2456 int double_digit_ref = capture_ref * 10 + c3 - '0';
2457 if (double_digit_ref <= capture_count) {
2458 next_index = second_digit_index;
2459 capture_ref = double_digit_ref;
2460 }
2461 }
2462 }
2463 if (capture_ref > 0) {
2464 if (i > last) {
2465 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2466 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002467 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2469 last = next_index + 1;
2470 }
2471 i = next_index;
2472 break;
2473 }
2474 default:
2475 i = next_index;
2476 break;
2477 }
2478 }
2479 }
2480 if (length > last) {
2481 if (last == 0) {
2482 parts->Add(ReplacementPart::ReplacementString());
2483 } else {
2484 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2485 }
2486 }
2487 }
2488
2489 ZoneList<ReplacementPart> parts_;
2490 ZoneList<Handle<String> > replacement_substrings_;
2491};
2492
2493
2494void CompiledReplacement::Compile(Handle<String> replacement,
2495 int capture_count,
2496 int subject_length) {
2497 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002498 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 AssertNoAllocation no_alloc;
2500 ParseReplacementPattern(&parts_,
2501 replacement->ToAsciiVector(),
2502 capture_count,
2503 subject_length);
2504 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002505 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 AssertNoAllocation no_alloc;
2507
2508 ParseReplacementPattern(&parts_,
2509 replacement->ToUC16Vector(),
2510 capture_count,
2511 subject_length);
2512 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002513 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002514 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int substring_index = 0;
2516 for (int i = 0, n = parts_.length(); i < n; i++) {
2517 int tag = parts_[i].tag;
2518 if (tag <= 0) { // A replacement string slice.
2519 int from = -tag;
2520 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002521 replacement_substrings_.Add(
2522 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 parts_[i].tag = REPLACEMENT_SUBSTRING;
2524 parts_[i].data = substring_index;
2525 substring_index++;
2526 } else if (tag == REPLACEMENT_STRING) {
2527 replacement_substrings_.Add(replacement);
2528 parts_[i].data = substring_index;
2529 substring_index++;
2530 }
2531 }
2532}
2533
2534
2535void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2536 int match_from,
2537 int match_to,
2538 Handle<JSArray> last_match_info) {
2539 for (int i = 0, n = parts_.length(); i < n; i++) {
2540 ReplacementPart part = parts_[i];
2541 switch (part.tag) {
2542 case SUBJECT_PREFIX:
2543 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2544 break;
2545 case SUBJECT_SUFFIX: {
2546 int subject_length = part.data;
2547 if (match_to < subject_length) {
2548 builder->AddSubjectSlice(match_to, subject_length);
2549 }
2550 break;
2551 }
2552 case SUBJECT_CAPTURE: {
2553 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002554 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2556 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2557 if (from >= 0 && to > from) {
2558 builder->AddSubjectSlice(from, to);
2559 }
2560 break;
2561 }
2562 case REPLACEMENT_SUBSTRING:
2563 case REPLACEMENT_STRING:
2564 builder->AddString(replacement_substrings_[part.data]);
2565 break;
2566 default:
2567 UNREACHABLE();
2568 }
2569 }
2570}
2571
2572
2573
lrn@chromium.org303ada72010-10-27 09:33:13 +00002574MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002575 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002576 String* subject,
2577 JSRegExp* regexp,
2578 String* replacement,
2579 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002580 ASSERT(subject->IsFlat());
2581 ASSERT(replacement->IsFlat());
2582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002583 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002584
2585 int length = subject->length();
2586 Handle<String> subject_handle(subject);
2587 Handle<JSRegExp> regexp_handle(regexp);
2588 Handle<String> replacement_handle(replacement);
2589 Handle<JSArray> last_match_info_handle(last_match_info);
2590 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2591 subject_handle,
2592 0,
2593 last_match_info_handle);
2594 if (match.is_null()) {
2595 return Failure::Exception();
2596 }
2597 if (match->IsNull()) {
2598 return *subject_handle;
2599 }
2600
2601 int capture_count = regexp_handle->CaptureCount();
2602
2603 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002604 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 CompiledReplacement compiled_replacement;
2606 compiled_replacement.Compile(replacement_handle,
2607 capture_count,
2608 length);
2609
2610 bool is_global = regexp_handle->GetFlags().is_global();
2611
2612 // Guessing the number of parts that the final result string is built
2613 // from. Global regexps can match any number of times, so we guess
2614 // conservatively.
2615 int expected_parts =
2616 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002617 ReplacementStringBuilder builder(isolate->heap(),
2618 subject_handle,
2619 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002620
2621 // Index of end of last match.
2622 int prev = 0;
2623
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002624 // Number of parts added by compiled replacement plus preceeding
2625 // string and possibly suffix after last match. It is possible for
2626 // all components to use two elements when encoded as two smis.
2627 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002628 bool matched = true;
2629 do {
2630 ASSERT(last_match_info_handle->HasFastElements());
2631 // Increase the capacity of the builder before entering local handle-scope,
2632 // so its internal buffer can safely allocate a new handle if it grows.
2633 builder.EnsureCapacity(parts_added_per_loop);
2634
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002635 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002636 int start, end;
2637 {
2638 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002639 FixedArray* match_info_array =
2640 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002641
2642 ASSERT_EQ(capture_count * 2 + 2,
2643 RegExpImpl::GetLastCaptureCount(match_info_array));
2644 start = RegExpImpl::GetCapture(match_info_array, 0);
2645 end = RegExpImpl::GetCapture(match_info_array, 1);
2646 }
2647
2648 if (prev < start) {
2649 builder.AddSubjectSlice(prev, start);
2650 }
2651 compiled_replacement.Apply(&builder,
2652 start,
2653 end,
2654 last_match_info_handle);
2655 prev = end;
2656
2657 // Only continue checking for global regexps.
2658 if (!is_global) break;
2659
2660 // Continue from where the match ended, unless it was an empty match.
2661 int next = end;
2662 if (start == end) {
2663 next = end + 1;
2664 if (next > length) break;
2665 }
2666
2667 match = RegExpImpl::Exec(regexp_handle,
2668 subject_handle,
2669 next,
2670 last_match_info_handle);
2671 if (match.is_null()) {
2672 return Failure::Exception();
2673 }
2674 matched = !match->IsNull();
2675 } while (matched);
2676
2677 if (prev < length) {
2678 builder.AddSubjectSlice(prev, length);
2679 }
2680
2681 return *(builder.ToString());
2682}
2683
2684
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002685template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002686MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002687 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002688 String* subject,
2689 JSRegExp* regexp,
2690 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002691 ASSERT(subject->IsFlat());
2692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002693 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002694
2695 Handle<String> subject_handle(subject);
2696 Handle<JSRegExp> regexp_handle(regexp);
2697 Handle<JSArray> last_match_info_handle(last_match_info);
2698 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2699 subject_handle,
2700 0,
2701 last_match_info_handle);
2702 if (match.is_null()) return Failure::Exception();
2703 if (match->IsNull()) return *subject_handle;
2704
2705 ASSERT(last_match_info_handle->HasFastElements());
2706
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002707 int start, end;
2708 {
2709 AssertNoAllocation match_info_array_is_not_in_a_handle;
2710 FixedArray* match_info_array =
2711 FixedArray::cast(last_match_info_handle->elements());
2712
2713 start = RegExpImpl::GetCapture(match_info_array, 0);
2714 end = RegExpImpl::GetCapture(match_info_array, 1);
2715 }
2716
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002717 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718 int new_length = length - (end - start);
2719 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002721 }
2722 Handle<ResultSeqString> answer;
2723 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 answer = Handle<ResultSeqString>::cast(
2725 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002726 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 answer = Handle<ResultSeqString>::cast(
2728 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002729 }
2730
2731 // If the regexp isn't global, only match once.
2732 if (!regexp_handle->GetFlags().is_global()) {
2733 if (start > 0) {
2734 String::WriteToFlat(*subject_handle,
2735 answer->GetChars(),
2736 0,
2737 start);
2738 }
2739 if (end < length) {
2740 String::WriteToFlat(*subject_handle,
2741 answer->GetChars() + start,
2742 end,
2743 length);
2744 }
2745 return *answer;
2746 }
2747
2748 int prev = 0; // Index of end of last match.
2749 int next = 0; // Start of next search (prev unless last match was empty).
2750 int position = 0;
2751
2752 do {
2753 if (prev < start) {
2754 // Add substring subject[prev;start] to answer string.
2755 String::WriteToFlat(*subject_handle,
2756 answer->GetChars() + position,
2757 prev,
2758 start);
2759 position += start - prev;
2760 }
2761 prev = end;
2762 next = end;
2763 // Continue from where the match ended, unless it was an empty match.
2764 if (start == end) {
2765 next++;
2766 if (next > length) break;
2767 }
2768 match = RegExpImpl::Exec(regexp_handle,
2769 subject_handle,
2770 next,
2771 last_match_info_handle);
2772 if (match.is_null()) return Failure::Exception();
2773 if (match->IsNull()) break;
2774
2775 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002776 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002777 {
2778 AssertNoAllocation match_info_array_is_not_in_a_handle;
2779 FixedArray* match_info_array =
2780 FixedArray::cast(last_match_info_handle->elements());
2781 start = RegExpImpl::GetCapture(match_info_array, 0);
2782 end = RegExpImpl::GetCapture(match_info_array, 1);
2783 }
2784 } while (true);
2785
2786 if (prev < length) {
2787 // Add substring subject[prev;length] to answer string.
2788 String::WriteToFlat(*subject_handle,
2789 answer->GetChars() + position,
2790 prev,
2791 length);
2792 position += length - prev;
2793 }
2794
2795 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002796 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002797 }
2798
2799 // Shorten string and fill
2800 int string_size = ResultSeqString::SizeFor(position);
2801 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2802 int delta = allocated_string_size - string_size;
2803
2804 answer->set_length(position);
2805 if (delta == 0) return *answer;
2806
2807 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002809
2810 return *answer;
2811}
2812
2813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002814RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002815 ASSERT(args.length() == 4);
2816
2817 CONVERT_CHECKED(String, subject, args[0]);
2818 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002819 Object* flat_subject;
2820 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2821 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2822 return maybe_flat_subject;
2823 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002824 }
2825 subject = String::cast(flat_subject);
2826 }
2827
2828 CONVERT_CHECKED(String, replacement, args[2]);
2829 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830 Object* flat_replacement;
2831 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2832 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2833 return maybe_flat_replacement;
2834 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002835 }
2836 replacement = String::cast(flat_replacement);
2837 }
2838
2839 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2840 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2841
2842 ASSERT(last_match_info->HasFastElements());
2843
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002844 if (replacement->length() == 0) {
2845 if (subject->HasOnlyAsciiChars()) {
2846 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002847 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002848 } else {
2849 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002850 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002851 }
2852 }
2853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002854 return StringReplaceRegExpWithString(isolate,
2855 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002856 regexp,
2857 replacement,
2858 last_match_info);
2859}
2860
2861
ager@chromium.org7c537e22008-10-16 08:43:32 +00002862// Perform string match of pattern on subject, starting at start index.
2863// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002864// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002865int Runtime::StringMatch(Isolate* isolate,
2866 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002867 Handle<String> pat,
2868 int start_index) {
2869 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002870 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002871
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002872 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002873 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002874
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002875 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002876 if (start_index + pattern_length > subject_length) return -1;
2877
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002878 if (!sub->IsFlat()) FlattenString(sub);
2879 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002880
ager@chromium.org7c537e22008-10-16 08:43:32 +00002881 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002882 // Extract flattened substrings of cons strings before determining asciiness.
2883 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002884 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002885 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002886 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002887
ager@chromium.org7c537e22008-10-16 08:43:32 +00002888 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002889 if (seq_pat->IsAsciiRepresentation()) {
2890 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2891 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002892 return SearchString(isolate,
2893 seq_sub->ToAsciiVector(),
2894 pat_vector,
2895 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 return SearchString(isolate,
2898 seq_sub->ToUC16Vector(),
2899 pat_vector,
2900 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002901 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002902 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2903 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002904 return SearchString(isolate,
2905 seq_sub->ToAsciiVector(),
2906 pat_vector,
2907 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 return SearchString(isolate,
2910 seq_sub->ToUC16Vector(),
2911 pat_vector,
2912 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002913}
2914
2915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002916RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002918 ASSERT(args.length() == 3);
2919
ager@chromium.org7c537e22008-10-16 08:43:32 +00002920 CONVERT_ARG_CHECKED(String, sub, 0);
2921 CONVERT_ARG_CHECKED(String, pat, 1);
2922
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002923 Object* index = args[2];
2924 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002925 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002926
ager@chromium.org870a0b62008-11-04 11:43:05 +00002927 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 int position =
2929 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002930 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002931}
2932
2933
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002934template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002935static int StringMatchBackwards(Vector<const schar> subject,
2936 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002937 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002938 int pattern_length = pattern.length();
2939 ASSERT(pattern_length >= 1);
2940 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002941
2942 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002943 for (int i = 0; i < pattern_length; i++) {
2944 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002945 if (c > String::kMaxAsciiCharCode) {
2946 return -1;
2947 }
2948 }
2949 }
2950
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002951 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002952 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002953 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002954 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002955 while (j < pattern_length) {
2956 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002957 break;
2958 }
2959 j++;
2960 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002961 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002962 return i;
2963 }
2964 }
2965 return -1;
2966}
2967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002968RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002970 ASSERT(args.length() == 3);
2971
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002972 CONVERT_ARG_CHECKED(String, sub, 0);
2973 CONVERT_ARG_CHECKED(String, pat, 1);
2974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002976 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002977 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002978
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002979 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002980 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002982 if (start_index + pat_length > sub_length) {
2983 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 if (pat_length == 0) {
2987 return Smi::FromInt(start_index);
2988 }
2989
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002990 if (!sub->IsFlat()) FlattenString(sub);
2991 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992
2993 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2994
2995 int position = -1;
2996
2997 if (pat->IsAsciiRepresentation()) {
2998 Vector<const char> pat_vector = pat->ToAsciiVector();
2999 if (sub->IsAsciiRepresentation()) {
3000 position = StringMatchBackwards(sub->ToAsciiVector(),
3001 pat_vector,
3002 start_index);
3003 } else {
3004 position = StringMatchBackwards(sub->ToUC16Vector(),
3005 pat_vector,
3006 start_index);
3007 }
3008 } else {
3009 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3010 if (sub->IsAsciiRepresentation()) {
3011 position = StringMatchBackwards(sub->ToAsciiVector(),
3012 pat_vector,
3013 start_index);
3014 } else {
3015 position = StringMatchBackwards(sub->ToUC16Vector(),
3016 pat_vector,
3017 start_index);
3018 }
3019 }
3020
3021 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003022}
3023
3024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003025RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003026 NoHandleAllocation ha;
3027 ASSERT(args.length() == 2);
3028
3029 CONVERT_CHECKED(String, str1, args[0]);
3030 CONVERT_CHECKED(String, str2, args[1]);
3031
3032 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int str1_length = str1->length();
3034 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035
3036 // Decide trivial cases without flattening.
3037 if (str1_length == 0) {
3038 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3039 return Smi::FromInt(-str2_length);
3040 } else {
3041 if (str2_length == 0) return Smi::FromInt(str1_length);
3042 }
3043
3044 int end = str1_length < str2_length ? str1_length : str2_length;
3045
3046 // No need to flatten if we are going to find the answer on the first
3047 // character. At this point we know there is at least one character
3048 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003049 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003050 if (d != 0) return Smi::FromInt(d);
3051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003052 str1->TryFlatten();
3053 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003055 StringInputBuffer& buf1 =
3056 *isolate->runtime_state()->string_locale_compare_buf1();
3057 StringInputBuffer& buf2 =
3058 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059
3060 buf1.Reset(str1);
3061 buf2.Reset(str2);
3062
3063 for (int i = 0; i < end; i++) {
3064 uint16_t char1 = buf1.GetNext();
3065 uint16_t char2 = buf2.GetNext();
3066 if (char1 != char2) return Smi::FromInt(char1 - char2);
3067 }
3068
3069 return Smi::FromInt(str1_length - str2_length);
3070}
3071
3072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003073RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 NoHandleAllocation ha;
3075 ASSERT(args.length() == 3);
3076
3077 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003078 Object* from = args[1];
3079 Object* to = args[2];
3080 int start, end;
3081 // We have a fast integer-only case here to avoid a conversion to double in
3082 // the common case where from and to are Smis.
3083 if (from->IsSmi() && to->IsSmi()) {
3084 start = Smi::cast(from)->value();
3085 end = Smi::cast(to)->value();
3086 } else {
3087 CONVERT_DOUBLE_CHECKED(from_number, from);
3088 CONVERT_DOUBLE_CHECKED(to_number, to);
3089 start = FastD2I(from_number);
3090 end = FastD2I(to_number);
3091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 RUNTIME_ASSERT(end >= start);
3093 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003094 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003096 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003097}
3098
3099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003100RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003101 ASSERT_EQ(3, args.length());
3102
3103 CONVERT_ARG_CHECKED(String, subject, 0);
3104 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3105 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3106 HandleScope handles;
3107
3108 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3109
3110 if (match.is_null()) {
3111 return Failure::Exception();
3112 }
3113 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003115 }
3116 int length = subject->length();
3117
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003118 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003119 ZoneList<int> offsets(8);
3120 do {
3121 int start;
3122 int end;
3123 {
3124 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003125 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003126 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3127 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3128 }
3129 offsets.Add(start);
3130 offsets.Add(end);
3131 int index = start < end ? end : end + 1;
3132 if (index > length) break;
3133 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3134 if (match.is_null()) {
3135 return Failure::Exception();
3136 }
3137 } while (!match->IsNull());
3138 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003139 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003140 for (int i = 0; i < matches ; i++) {
3141 int from = offsets.at(i * 2);
3142 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003143 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003144 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003145 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003146 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 result->set_length(Smi::FromInt(matches));
3148 return *result;
3149}
3150
3151
lrn@chromium.org25156de2010-04-06 13:10:27 +00003152// Two smis before and after the match, for very long strings.
3153const int kMaxBuilderEntriesPerRegExpMatch = 5;
3154
3155
3156static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3157 Handle<JSArray> last_match_info,
3158 int match_start,
3159 int match_end) {
3160 // Fill last_match_info with a single capture.
3161 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3162 AssertNoAllocation no_gc;
3163 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3164 RegExpImpl::SetLastCaptureCount(elements, 2);
3165 RegExpImpl::SetLastInput(elements, *subject);
3166 RegExpImpl::SetLastSubject(elements, *subject);
3167 RegExpImpl::SetCapture(elements, 0, match_start);
3168 RegExpImpl::SetCapture(elements, 1, match_end);
3169}
3170
3171
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003172template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173static bool SearchStringMultiple(Isolate* isolate,
3174 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003175 Vector<const PatternChar> pattern,
3176 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003177 FixedArrayBuilder* builder,
3178 int* match_pos) {
3179 int pos = *match_pos;
3180 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003181 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003182 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003183 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003184 while (pos <= max_search_start) {
3185 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3186 *match_pos = pos;
3187 return false;
3188 }
3189 // Position of end of previous match.
3190 int match_end = pos + pattern_length;
3191 int new_pos = search.Search(subject, match_end);
3192 if (new_pos >= 0) {
3193 // A match.
3194 if (new_pos > match_end) {
3195 ReplacementStringBuilder::AddSubjectSlice(builder,
3196 match_end,
3197 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003198 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003199 pos = new_pos;
3200 builder->Add(pattern_string);
3201 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003202 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003203 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003204 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003205
lrn@chromium.org25156de2010-04-06 13:10:27 +00003206 if (pos < max_search_start) {
3207 ReplacementStringBuilder::AddSubjectSlice(builder,
3208 pos + pattern_length,
3209 subject_length);
3210 }
3211 *match_pos = pos;
3212 return true;
3213}
3214
3215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216static bool SearchStringMultiple(Isolate* isolate,
3217 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 Handle<String> pattern,
3219 Handle<JSArray> last_match_info,
3220 FixedArrayBuilder* builder) {
3221 ASSERT(subject->IsFlat());
3222 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003223
3224 // Treating as if a previous match was before first character.
3225 int match_pos = -pattern->length();
3226
3227 for (;;) { // Break when search complete.
3228 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3229 AssertNoAllocation no_gc;
3230 if (subject->IsAsciiRepresentation()) {
3231 Vector<const char> subject_vector = subject->ToAsciiVector();
3232 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003233 if (SearchStringMultiple(isolate,
3234 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003235 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003236 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003237 builder,
3238 &match_pos)) break;
3239 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003240 if (SearchStringMultiple(isolate,
3241 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003242 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003243 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003244 builder,
3245 &match_pos)) break;
3246 }
3247 } else {
3248 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3249 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003250 if (SearchStringMultiple(isolate,
3251 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003253 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003254 builder,
3255 &match_pos)) break;
3256 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257 if (SearchStringMultiple(isolate,
3258 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003260 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003261 builder,
3262 &match_pos)) break;
3263 }
3264 }
3265 }
3266
3267 if (match_pos >= 0) {
3268 SetLastMatchInfoNoCaptures(subject,
3269 last_match_info,
3270 match_pos,
3271 match_pos + pattern->length());
3272 return true;
3273 }
3274 return false; // No matches at all.
3275}
3276
3277
3278static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003280 Handle<String> subject,
3281 Handle<JSRegExp> regexp,
3282 Handle<JSArray> last_match_array,
3283 FixedArrayBuilder* builder) {
3284 ASSERT(subject->IsFlat());
3285 int match_start = -1;
3286 int match_end = 0;
3287 int pos = 0;
3288 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3289 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3290
3291 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003292 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 int subject_length = subject->length();
3294
3295 for (;;) { // Break on failure, return on exception.
3296 RegExpImpl::IrregexpResult result =
3297 RegExpImpl::IrregexpExecOnce(regexp,
3298 subject,
3299 pos,
3300 register_vector);
3301 if (result == RegExpImpl::RE_SUCCESS) {
3302 match_start = register_vector[0];
3303 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3304 if (match_end < match_start) {
3305 ReplacementStringBuilder::AddSubjectSlice(builder,
3306 match_end,
3307 match_start);
3308 }
3309 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 HandleScope loop_scope(isolate);
3311 builder->Add(*isolate->factory()->NewSubString(subject,
3312 match_start,
3313 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003314 if (match_start != match_end) {
3315 pos = match_end;
3316 } else {
3317 pos = match_end + 1;
3318 if (pos > subject_length) break;
3319 }
3320 } else if (result == RegExpImpl::RE_FAILURE) {
3321 break;
3322 } else {
3323 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3324 return result;
3325 }
3326 }
3327
3328 if (match_start >= 0) {
3329 if (match_end < subject_length) {
3330 ReplacementStringBuilder::AddSubjectSlice(builder,
3331 match_end,
3332 subject_length);
3333 }
3334 SetLastMatchInfoNoCaptures(subject,
3335 last_match_array,
3336 match_start,
3337 match_end);
3338 return RegExpImpl::RE_SUCCESS;
3339 } else {
3340 return RegExpImpl::RE_FAILURE; // No matches at all.
3341 }
3342}
3343
3344
3345static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003347 Handle<String> subject,
3348 Handle<JSRegExp> regexp,
3349 Handle<JSArray> last_match_array,
3350 FixedArrayBuilder* builder) {
3351
3352 ASSERT(subject->IsFlat());
3353 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3354 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3355
3356 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003357 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003358
3359 RegExpImpl::IrregexpResult result =
3360 RegExpImpl::IrregexpExecOnce(regexp,
3361 subject,
3362 0,
3363 register_vector);
3364
3365 int capture_count = regexp->CaptureCount();
3366 int subject_length = subject->length();
3367
3368 // Position to search from.
3369 int pos = 0;
3370 // End of previous match. Differs from pos if match was empty.
3371 int match_end = 0;
3372 if (result == RegExpImpl::RE_SUCCESS) {
3373 // Need to keep a copy of the previous match for creating last_match_info
3374 // at the end, so we have two vectors that we swap between.
3375 OffsetsVector registers2(required_registers);
3376 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3377
3378 do {
3379 int match_start = register_vector[0];
3380 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3381 if (match_end < match_start) {
3382 ReplacementStringBuilder::AddSubjectSlice(builder,
3383 match_end,
3384 match_start);
3385 }
3386 match_end = register_vector[1];
3387
3388 {
3389 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003390 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003391 // Arguments array to replace function is match, captures, index and
3392 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 Handle<FixedArray> elements =
3394 isolate->factory()->NewFixedArray(3 + capture_count);
3395 Handle<String> match = isolate->factory()->NewSubString(subject,
3396 match_start,
3397 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003398 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003399 for (int i = 1; i <= capture_count; i++) {
3400 int start = register_vector[i * 2];
3401 if (start >= 0) {
3402 int end = register_vector[i * 2 + 1];
3403 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 Handle<String> substring = isolate->factory()->NewSubString(subject,
3405 start,
3406 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003407 elements->set(i, *substring);
3408 } else {
3409 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003410 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003411 }
3412 }
3413 elements->set(capture_count + 1, Smi::FromInt(match_start));
3414 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003416 }
3417 // Swap register vectors, so the last successful match is in
3418 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003419 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 prev_register_vector = register_vector;
3421 register_vector = tmp;
3422
3423 if (match_end > match_start) {
3424 pos = match_end;
3425 } else {
3426 pos = match_end + 1;
3427 if (pos > subject_length) {
3428 break;
3429 }
3430 }
3431
3432 result = RegExpImpl::IrregexpExecOnce(regexp,
3433 subject,
3434 pos,
3435 register_vector);
3436 } while (result == RegExpImpl::RE_SUCCESS);
3437
3438 if (result != RegExpImpl::RE_EXCEPTION) {
3439 // Finished matching, with at least one match.
3440 if (match_end < subject_length) {
3441 ReplacementStringBuilder::AddSubjectSlice(builder,
3442 match_end,
3443 subject_length);
3444 }
3445
3446 int last_match_capture_count = (capture_count + 1) * 2;
3447 int last_match_array_size =
3448 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3449 last_match_array->EnsureSize(last_match_array_size);
3450 AssertNoAllocation no_gc;
3451 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3452 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3453 RegExpImpl::SetLastSubject(elements, *subject);
3454 RegExpImpl::SetLastInput(elements, *subject);
3455 for (int i = 0; i < last_match_capture_count; i++) {
3456 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3457 }
3458 return RegExpImpl::RE_SUCCESS;
3459 }
3460 }
3461 // No matches at all, return failure or exception result directly.
3462 return result;
3463}
3464
3465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003466RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003468 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003469
3470 CONVERT_ARG_CHECKED(String, subject, 1);
3471 if (!subject->IsFlat()) { FlattenString(subject); }
3472 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3473 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3474 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3475
3476 ASSERT(last_match_info->HasFastElements());
3477 ASSERT(regexp->GetFlags().is_global());
3478 Handle<FixedArray> result_elements;
3479 if (result_array->HasFastElements()) {
3480 result_elements =
3481 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3482 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 }
3485 FixedArrayBuilder builder(result_elements);
3486
3487 if (regexp->TypeTag() == JSRegExp::ATOM) {
3488 Handle<String> pattern(
3489 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003490 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003491 if (SearchStringMultiple(isolate, subject, pattern,
3492 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003493 return *builder.ToJSArray(result_array);
3494 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003495 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003496 }
3497
3498 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3499
3500 RegExpImpl::IrregexpResult result;
3501 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 result = SearchRegExpNoCaptureMultiple(isolate,
3503 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003504 regexp,
3505 last_match_info,
3506 &builder);
3507 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 result = SearchRegExpMultiple(isolate,
3509 subject,
3510 regexp,
3511 last_match_info,
3512 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003513 }
3514 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003516 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3517 return Failure::Exception();
3518}
3519
3520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522 NoHandleAllocation ha;
3523 ASSERT(args.length() == 2);
3524
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003525 // Fast case where the result is a one character string.
3526 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3527 int value = Smi::cast(args[0])->value();
3528 int radix = Smi::cast(args[1])->value();
3529 if (value >= 0 && value < radix) {
3530 RUNTIME_ASSERT(radix <= 36);
3531 // Character array used for conversion.
3532 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 return isolate->heap()->
3534 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003535 }
3536 }
3537
3538 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539 CONVERT_DOUBLE_CHECKED(value, args[0]);
3540 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003541 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003542 }
3543 if (isinf(value)) {
3544 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003545 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003548 }
3549 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3550 int radix = FastD2I(radix_number);
3551 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3552 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003553 MaybeObject* result =
3554 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 DeleteArray(str);
3556 return result;
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 2);
3563
3564 CONVERT_DOUBLE_CHECKED(value, args[0]);
3565 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567 }
3568 if (isinf(value)) {
3569 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573 }
3574 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3575 int f = FastD2I(f_number);
3576 RUNTIME_ASSERT(f >= 0);
3577 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 MaybeObject* res =
3579 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582}
3583
3584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 NoHandleAllocation ha;
3587 ASSERT(args.length() == 2);
3588
3589 CONVERT_DOUBLE_CHECKED(value, args[0]);
3590 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 }
3593 if (isinf(value)) {
3594 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
3599 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3600 int f = FastD2I(f_number);
3601 RUNTIME_ASSERT(f >= -1 && f <= 20);
3602 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 MaybeObject* res =
3604 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607}
3608
3609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003610RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 NoHandleAllocation ha;
3612 ASSERT(args.length() == 2);
3613
3614 CONVERT_DOUBLE_CHECKED(value, args[0]);
3615 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 }
3618 if (isinf(value)) {
3619 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003622 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 }
3624 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3625 int f = FastD2I(f_number);
3626 RUNTIME_ASSERT(f >= 1 && f <= 21);
3627 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 MaybeObject* res =
3629 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003631 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632}
3633
3634
3635// Returns a single character string where first character equals
3636// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003637static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003638 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003639 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003640 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003641 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003643 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644}
3645
3646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003647MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3648 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003649 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650 // Handle [] indexing on Strings
3651 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003652 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3653 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 }
3655
3656 // Handle [] indexing on String objects
3657 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003658 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3659 Handle<Object> result =
3660 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3661 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 }
3663
3664 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003665 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 return prototype->GetElement(index);
3667 }
3668
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003669 return GetElement(object, index);
3670}
3671
3672
lrn@chromium.org303ada72010-10-27 09:33:13 +00003673MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 return object->GetElement(index);
3675}
3676
3677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3679 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003680 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003681 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003686 isolate->factory()->NewTypeError("non_object_property_load",
3687 HandleVector(args, 2));
3688 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 }
3690
3691 // Check if the given key is an array index.
3692 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003693 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003694 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 }
3696
3697 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003698 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003700 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702 bool has_pending_exception = false;
3703 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003704 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003706 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003707 }
3708
ager@chromium.org32912102009-01-16 10:38:43 +00003709 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003710 // the element if so.
3711 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 } else {
3714 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003715 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 }
3717}
3718
3719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003720RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 NoHandleAllocation ha;
3722 ASSERT(args.length() == 2);
3723
3724 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003725 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728}
3729
3730
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003731// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003732RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003733 NoHandleAllocation ha;
3734 ASSERT(args.length() == 2);
3735
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003736 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003737 // itself.
3738 //
3739 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003740 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003741 // global proxy object never has properties. This is the case
3742 // because the global proxy object forwards everything to its hidden
3743 // prototype including local lookups.
3744 //
3745 // Additionally, we need to make sure that we do not cache results
3746 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003747 if (args[0]->IsJSObject() &&
3748 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003749 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003750 args[1]->IsString()) {
3751 JSObject* receiver = JSObject::cast(args[0]);
3752 String* key = String::cast(args[1]);
3753 if (receiver->HasFastProperties()) {
3754 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003755 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003756 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3757 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003758 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003759 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003760 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003761 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003762 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003763 LookupResult result;
3764 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003765 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003766 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003768 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003769 }
3770 } else {
3771 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003772 StringDictionary* dictionary = receiver->property_dictionary();
3773 int entry = dictionary->FindEntry(key);
3774 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003775 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003776 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003777 if (!receiver->IsGlobalObject()) return value;
3778 value = JSGlobalPropertyCell::cast(value)->value();
3779 if (!value->IsTheHole()) return value;
3780 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003781 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003782 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003783 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3784 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003786 Handle<String> str = args.at<String>(0);
3787 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003788 if (index >= 0 && index < str->length()) {
3789 Handle<Object> result = GetCharAt(str, index);
3790 return *result;
3791 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003792 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003793
3794 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 return Runtime::GetObjectProperty(isolate,
3796 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003797 args.at<Object>(1));
3798}
3799
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003800// Implements part of 8.12.9 DefineOwnProperty.
3801// There are 3 cases that lead here:
3802// Step 4b - define a new accessor property.
3803// Steps 9c & 12 - replace an existing data property with an accessor property.
3804// Step 12 - update an existing accessor property with an accessor or generic
3805// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003806RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003807 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003809 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3810 CONVERT_CHECKED(String, name, args[1]);
3811 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003812 Object* fun = args[3];
3813 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003814 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3815 int unchecked = flag_attr->value();
3816 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3817 RUNTIME_ASSERT(!obj->IsNull());
3818 LookupResult result;
3819 obj->LocalLookupRealNamedProperty(name, &result);
3820
3821 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3822 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3823 // delete it to avoid running into trouble in DefineAccessor, which
3824 // handles this incorrectly if the property is readonly (does nothing)
3825 if (result.IsProperty() &&
3826 (result.type() == FIELD || result.type() == NORMAL
3827 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003828 Object* ok;
3829 { MaybeObject* maybe_ok =
3830 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3831 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3832 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003833 }
3834 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3835}
3836
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003837// Implements part of 8.12.9 DefineOwnProperty.
3838// There are 3 cases that lead here:
3839// Step 4a - define a new data property.
3840// Steps 9b & 12 - replace an existing accessor property with a data property.
3841// Step 12 - update an existing data property with a data or generic
3842// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003843RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003844 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003845 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003846 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3847 CONVERT_ARG_CHECKED(String, name, 1);
3848 Handle<Object> obj_value = args.at<Object>(2);
3849
3850 CONVERT_CHECKED(Smi, flag, args[3]);
3851 int unchecked = flag->value();
3852 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3853
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003854 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3855
3856 // Check if this is an element.
3857 uint32_t index;
3858 bool is_element = name->AsArrayIndex(&index);
3859
3860 // Special case for elements if any of the flags are true.
3861 // If elements are in fast case we always implicitly assume that:
3862 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3863 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3864 is_element) {
3865 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003866 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003867 // We do not need to do access checks here since these has already
3868 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003869 Handle<Object> proto(js_object->GetPrototype());
3870 // If proxy is detached, ignore the assignment. Alternatively,
3871 // we could throw an exception.
3872 if (proto->IsNull()) return *obj_value;
3873 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003874 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003875 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003876 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003877 // Make sure that we never go back to fast case.
3878 dictionary->set_requires_slow_elements();
3879 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003880 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003881 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003882 }
3883
ager@chromium.org5c838252010-02-19 08:53:10 +00003884 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003885 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003886
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003887 // To be compatible with safari we do not change the value on API objects
3888 // in defineProperty. Firefox disagrees here, and actually changes the value.
3889 if (result.IsProperty() &&
3890 (result.type() == CALLBACKS) &&
3891 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003893 }
3894
ager@chromium.org5c838252010-02-19 08:53:10 +00003895 // Take special care when attributes are different and there is already
3896 // a property. For simplicity we normalize the property which enables us
3897 // to not worry about changing the instance_descriptor and creating a new
3898 // map. The current version of SetObjectProperty does not handle attributes
3899 // correctly in the case where a property is a field and is reset with
3900 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003901 if (result.IsProperty() &&
3902 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003903 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003904 if (js_object->IsJSGlobalProxy()) {
3905 // Since the result is a property, the prototype will exist so
3906 // we don't have to check for null.
3907 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003908 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003909 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003910 // Use IgnoreAttributes version since a readonly property may be
3911 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003912 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3913 *obj_value,
3914 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003915 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::ForceSetObjectProperty(isolate,
3918 js_object,
3919 name,
3920 obj_value,
3921 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003922}
3923
3924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003925MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3926 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003927 Handle<Object> key,
3928 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003929 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003930 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003931 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003934 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 isolate->factory()->NewTypeError("non_object_property_store",
3937 HandleVector(args, 2));
3938 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003939 }
3940
3941 // If the object isn't a JavaScript object, we ignore the store.
3942 if (!object->IsJSObject()) return *value;
3943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 // Check if the given key is an array index.
3947 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003948 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3950 // of a string using [] notation. We need to support this too in
3951 // JavaScript.
3952 // In the case of a String object we just need to redirect the assignment to
3953 // the underlying string if the index is in range. Since the underlying
3954 // string does nothing with the assignment then we can ignore such
3955 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003956 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003960 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003961 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 return *value;
3963 }
3964
3965 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003966 Handle<Object> result;
3967 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003968 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003970 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003971 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003972 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003974 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 return *value;
3976 }
3977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 bool has_pending_exception = false;
3980 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3981 if (has_pending_exception) return Failure::Exception();
3982 Handle<String> name = Handle<String>::cast(converted);
3983
3984 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003985 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003987 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 }
3989}
3990
3991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3993 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003994 Handle<Object> key,
3995 Handle<Object> value,
3996 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003998
3999 // Check if the given key is an array index.
4000 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004001 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004002 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4003 // of a string using [] notation. We need to support this too in
4004 // JavaScript.
4005 // In the case of a String object we just need to redirect the assignment to
4006 // the underlying string if the index is in range. Since the underlying
4007 // string does nothing with the assignment then we can ignore such
4008 // assignments.
4009 if (js_object->IsStringObjectWithCharacterAt(index)) {
4010 return *value;
4011 }
4012
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004013 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004014 }
4015
4016 if (key->IsString()) {
4017 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004018 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004019 } else {
4020 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004021 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004022 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4023 *value,
4024 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004025 }
4026 }
4027
4028 // Call-back into JavaScript to convert the key to a string.
4029 bool has_pending_exception = false;
4030 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4031 if (has_pending_exception) return Failure::Exception();
4032 Handle<String> name = Handle<String>::cast(converted);
4033
4034 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004035 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004036 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004037 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004038 }
4039}
4040
4041
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004042MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4043 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004044 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004045 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004046
4047 // Check if the given key is an array index.
4048 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004049 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004050 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4051 // characters of a string using [] notation. In the case of a
4052 // String object we just need to redirect the deletion to the
4053 // underlying string if the index is in range. Since the
4054 // underlying string does nothing with the deletion, we can ignore
4055 // such deletions.
4056 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004058 }
4059
4060 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4061 }
4062
4063 Handle<String> key_string;
4064 if (key->IsString()) {
4065 key_string = Handle<String>::cast(key);
4066 } else {
4067 // Call-back into JavaScript to convert the key to a string.
4068 bool has_pending_exception = false;
4069 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4070 if (has_pending_exception) return Failure::Exception();
4071 key_string = Handle<String>::cast(converted);
4072 }
4073
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004074 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004075 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4076}
4077
4078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004079RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004081 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082
4083 Handle<Object> object = args.at<Object>(0);
4084 Handle<Object> key = args.at<Object>(1);
4085 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004086 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4087 RUNTIME_ASSERT(
4088 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004090 PropertyAttributes attributes =
4091 static_cast<PropertyAttributes>(unchecked_attributes);
4092
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004093 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004094 if (args.length() == 5) {
4095 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4096 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4097 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004098 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004101 return Runtime::SetObjectProperty(isolate,
4102 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004103 key,
4104 value,
4105 attributes,
4106 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107}
4108
4109
4110// Set a local property, even if it is READ_ONLY. If the property does not
4111// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004112RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004114 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 CONVERT_CHECKED(JSObject, object, args[0]);
4116 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004117 // Compute attributes.
4118 PropertyAttributes attributes = NONE;
4119 if (args.length() == 4) {
4120 CONVERT_CHECKED(Smi, value_obj, args[3]);
4121 int unchecked_value = value_obj->value();
4122 // Only attribute bits should be set.
4123 RUNTIME_ASSERT(
4124 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4125 attributes = static_cast<PropertyAttributes>(unchecked_value);
4126 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004128 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004129 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130}
4131
4132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004133RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004135 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136
4137 CONVERT_CHECKED(JSObject, object, args[0]);
4138 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004139 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004140 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004141 ? JSObject::STRICT_DELETION
4142 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004146static Object* HasLocalPropertyImplementation(Isolate* isolate,
4147 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004148 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004150 // Handle hidden prototypes. If there's a hidden prototype above this thing
4151 // then we have to check it for properties, because they are supposed to
4152 // look like they are on this object.
4153 Handle<Object> proto(object->GetPrototype());
4154 if (proto->IsJSObject() &&
4155 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 return HasLocalPropertyImplementation(isolate,
4157 Handle<JSObject>::cast(proto),
4158 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004159 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004160 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004161}
4162
4163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004164RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 NoHandleAllocation ha;
4166 ASSERT(args.length() == 2);
4167 CONVERT_CHECKED(String, key, args[1]);
4168
ager@chromium.org9085a012009-05-11 19:22:57 +00004169 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004171 if (obj->IsJSObject()) {
4172 JSObject* object = JSObject::cast(obj);
4173 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004175 // Slow case. Either it's not there or we have an interceptor. We should
4176 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 HandleScope scope(isolate);
4178 return HasLocalPropertyImplementation(isolate,
4179 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004180 Handle<String>(key));
4181 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 // Well, there is one exception: Handle [] on strings.
4183 uint32_t index;
4184 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004185 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004186 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 }
4189 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191}
4192
4193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004194RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 NoHandleAllocation na;
4196 ASSERT(args.length() == 2);
4197
4198 // Only JS objects can have properties.
4199 if (args[0]->IsJSObject()) {
4200 JSObject* object = JSObject::cast(args[0]);
4201 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004202 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004204 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205}
4206
4207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004208RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 NoHandleAllocation na;
4210 ASSERT(args.length() == 2);
4211
4212 // Only JS objects can have elements.
4213 if (args[0]->IsJSObject()) {
4214 JSObject* object = JSObject::cast(args[0]);
4215 CONVERT_CHECKED(Smi, index_obj, args[1]);
4216 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004219 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220}
4221
4222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004223RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004224 NoHandleAllocation ha;
4225 ASSERT(args.length() == 2);
4226
4227 CONVERT_CHECKED(JSObject, object, args[0]);
4228 CONVERT_CHECKED(String, key, args[1]);
4229
4230 uint32_t index;
4231 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004232 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233 }
4234
ager@chromium.org870a0b62008-11-04 11:43:05 +00004235 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237}
4238
4239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004240RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004241 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004243 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 return *GetKeysFor(object);
4245}
4246
4247
4248// Returns either a FixedArray as Runtime_GetPropertyNames,
4249// or, if the given object has an enum cache that contains
4250// all enumerable properties of the object and its prototypes
4251// have none, the map of the object. This is used to speed up
4252// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004253RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254 ASSERT(args.length() == 1);
4255
4256 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4257
4258 if (raw_object->IsSimpleEnum()) return raw_object->map();
4259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004261 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004262 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4263 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004264
4265 // Test again, since cache may have been built by preceding call.
4266 if (object->IsSimpleEnum()) return object->map();
4267
4268 return *content;
4269}
4270
4271
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004272// Find the length of the prototype chain that is to to handled as one. If a
4273// prototype object is hidden it is to be viewed as part of the the object it
4274// is prototype for.
4275static int LocalPrototypeChainLength(JSObject* obj) {
4276 int count = 1;
4277 Object* proto = obj->GetPrototype();
4278 while (proto->IsJSObject() &&
4279 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4280 count++;
4281 proto = JSObject::cast(proto)->GetPrototype();
4282 }
4283 return count;
4284}
4285
4286
4287// Return the names of the local named properties.
4288// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004289RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004290 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004291 ASSERT(args.length() == 1);
4292 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004293 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004294 }
4295 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4296
4297 // Skip the global proxy as it has no properties and always delegates to the
4298 // real global object.
4299 if (obj->IsJSGlobalProxy()) {
4300 // Only collect names if access is permitted.
4301 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 !isolate->MayNamedAccess(*obj,
4303 isolate->heap()->undefined_value(),
4304 v8::ACCESS_KEYS)) {
4305 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4306 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004307 }
4308 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4309 }
4310
4311 // Find the number of objects making up this.
4312 int length = LocalPrototypeChainLength(*obj);
4313
4314 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004315 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004316 int total_property_count = 0;
4317 Handle<JSObject> jsproto = obj;
4318 for (int i = 0; i < length; i++) {
4319 // Only collect names if access is permitted.
4320 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 !isolate->MayNamedAccess(*jsproto,
4322 isolate->heap()->undefined_value(),
4323 v8::ACCESS_KEYS)) {
4324 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4325 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004326 }
4327 int n;
4328 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4329 local_property_count[i] = n;
4330 total_property_count += n;
4331 if (i < length - 1) {
4332 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4333 }
4334 }
4335
4336 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 Handle<FixedArray> names =
4338 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004339
4340 // Get the property names.
4341 jsproto = obj;
4342 int proto_with_hidden_properties = 0;
4343 for (int i = 0; i < length; i++) {
4344 jsproto->GetLocalPropertyNames(*names,
4345 i == 0 ? 0 : local_property_count[i - 1]);
4346 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4347 proto_with_hidden_properties++;
4348 }
4349 if (i < length - 1) {
4350 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4351 }
4352 }
4353
4354 // Filter out name of hidden propeties object.
4355 if (proto_with_hidden_properties > 0) {
4356 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004357 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004358 names->length() - proto_with_hidden_properties);
4359 int dest_pos = 0;
4360 for (int i = 0; i < total_property_count; i++) {
4361 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004362 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004363 continue;
4364 }
4365 names->set(dest_pos++, name);
4366 }
4367 }
4368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004369 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004370}
4371
4372
4373// Return the names of the local indexed properties.
4374// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004375RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004376 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004377 ASSERT(args.length() == 1);
4378 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004379 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004380 }
4381 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4382
4383 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004384 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004385 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004386 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004387}
4388
4389
4390// Return information on whether an object has a named or indexed interceptor.
4391// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004392RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004394 ASSERT(args.length() == 1);
4395 if (!args[0]->IsJSObject()) {
4396 return Smi::FromInt(0);
4397 }
4398 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4399
4400 int result = 0;
4401 if (obj->HasNamedInterceptor()) result |= 2;
4402 if (obj->HasIndexedInterceptor()) result |= 1;
4403
4404 return Smi::FromInt(result);
4405}
4406
4407
4408// Return property names from named interceptor.
4409// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004410RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004411 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004412 ASSERT(args.length() == 1);
4413 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4414
4415 if (obj->HasNamedInterceptor()) {
4416 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4417 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4418 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004419 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004420}
4421
4422
4423// Return element names from indexed interceptor.
4424// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004425RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004426 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004427 ASSERT(args.length() == 1);
4428 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4429
4430 if (obj->HasIndexedInterceptor()) {
4431 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4432 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4433 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004434 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004435}
4436
4437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004438RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004439 ASSERT_EQ(args.length(), 1);
4440 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004441 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004442 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004443
4444 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004445 // Do access checks before going to the global object.
4446 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004448 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4450 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004451 }
4452
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004453 Handle<Object> proto(object->GetPrototype());
4454 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004455 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004456 object = Handle<JSObject>::cast(proto);
4457 }
4458
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004459 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4460 LOCAL_ONLY);
4461 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4462 // property array and since the result is mutable we have to create
4463 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004464 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004465 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004466 for (int i = 0; i < length; i++) {
4467 Object* entry = contents->get(i);
4468 if (entry->IsString()) {
4469 copy->set(i, entry);
4470 } else {
4471 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 HandleScope scope(isolate);
4473 Handle<Object> entry_handle(entry, isolate);
4474 Handle<Object> entry_str =
4475 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004476 copy->set(i, *entry_str);
4477 }
4478 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004480}
4481
4482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004483RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 NoHandleAllocation ha;
4485 ASSERT(args.length() == 1);
4486
4487 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004488 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 it.AdvanceToArgumentsFrame();
4490 JavaScriptFrame* frame = it.frame();
4491
4492 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004493 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494
4495 // Try to convert the key to an index. If successful and within
4496 // index return the the argument from the frame.
4497 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004498 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 return frame->GetParameter(index);
4500 }
4501
4502 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 bool exception = false;
4505 Handle<Object> converted =
4506 Execution::ToString(args.at<Object>(0), &exception);
4507 if (exception) return Failure::Exception();
4508 Handle<String> key = Handle<String>::cast(converted);
4509
4510 // Try to convert the string key into an array index.
4511 if (key->AsArrayIndex(&index)) {
4512 if (index < n) {
4513 return frame->GetParameter(index);
4514 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516 }
4517 }
4518
4519 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4521 if (key->Equals(isolate->heap()->callee_symbol())) {
4522 Object* function = frame->function();
4523 if (function->IsJSFunction() &&
4524 JSFunction::cast(function)->shared()->strict_mode()) {
4525 return isolate->Throw(*isolate->factory()->NewTypeError(
4526 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4527 }
4528 return function;
4529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530
4531 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004532 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533}
4534
4535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004536RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004538
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004539 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004540 Handle<Object> object = args.at<Object>(0);
4541 if (object->IsJSObject()) {
4542 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004543 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004544 MaybeObject* ok = js_object->TransformToFastProperties(0);
4545 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004546 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004547 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004548 return *object;
4549}
4550
4551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004552RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004554
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004555 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004556 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004557 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004558 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004559 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004560 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004561 return *object;
4562}
4563
4564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004565RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 NoHandleAllocation ha;
4567 ASSERT(args.length() == 1);
4568
4569 return args[0]->ToBoolean();
4570}
4571
4572
4573// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4574// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004575RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 NoHandleAllocation ha;
4577
4578 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004579 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 HeapObject* heap_obj = HeapObject::cast(obj);
4581
4582 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 if (heap_obj->map()->is_undetectable()) {
4584 return isolate->heap()->undefined_symbol();
4585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586
4587 InstanceType instance_type = heap_obj->map()->instance_type();
4588 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004589 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590 }
4591
4592 switch (instance_type) {
4593 case ODDBALL_TYPE:
4594 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004595 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596 }
4597 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004598 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599 }
4600 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004601 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004602 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 default:
4605 // For any kind of object not handled above, the spec rule for
4606 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004607 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608 }
4609}
4610
4611
lrn@chromium.org25156de2010-04-06 13:10:27 +00004612static bool AreDigits(const char*s, int from, int to) {
4613 for (int i = from; i < to; i++) {
4614 if (s[i] < '0' || s[i] > '9') return false;
4615 }
4616
4617 return true;
4618}
4619
4620
4621static int ParseDecimalInteger(const char*s, int from, int to) {
4622 ASSERT(to - from < 10); // Overflow is not possible.
4623 ASSERT(from < to);
4624 int d = s[from] - '0';
4625
4626 for (int i = from + 1; i < to; i++) {
4627 d = 10 * d + (s[i] - '0');
4628 }
4629
4630 return d;
4631}
4632
4633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004634RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 NoHandleAllocation ha;
4636 ASSERT(args.length() == 1);
4637 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004638 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004639
4640 // Fast case: short integer or some sorts of junk values.
4641 int len = subject->length();
4642 if (subject->IsSeqAsciiString()) {
4643 if (len == 0) return Smi::FromInt(0);
4644
4645 char const* data = SeqAsciiString::cast(subject)->GetChars();
4646 bool minus = (data[0] == '-');
4647 int start_pos = (minus ? 1 : 0);
4648
4649 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004651 } else if (data[start_pos] > '9') {
4652 // Fast check for a junk value. A valid string may start from a
4653 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4654 // the 'I' character ('Infinity'). All of that have codes not greater than
4655 // '9' except 'I'.
4656 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004658 }
4659 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4660 // The maximal/minimal smi has 10 digits. If the string has less digits we
4661 // know it will fit into the smi-data type.
4662 int d = ParseDecimalInteger(data, start_pos, len);
4663 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004665 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004666 } else if (!subject->HasHashCode() &&
4667 len <= String::kMaxArrayIndexSize &&
4668 (len == 1 || data[0] != '0')) {
4669 // String hash is not calculated yet but all the data are present.
4670 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004671 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004673 subject->Hash(); // Force hash calculation.
4674 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4675 static_cast<int>(hash));
4676#endif
4677 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004678 }
4679 return Smi::FromInt(d);
4680 }
4681 }
4682
4683 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004684 return isolate->heap()->NumberFromDouble(
4685 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686}
4687
4688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004689RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 NoHandleAllocation ha;
4691 ASSERT(args.length() == 1);
4692
4693 CONVERT_CHECKED(JSArray, codes, args[0]);
4694 int length = Smi::cast(codes->length())->value();
4695
4696 // Check if the string can be ASCII.
4697 int i;
4698 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004699 Object* element;
4700 { MaybeObject* maybe_element = codes->GetElement(i);
4701 // We probably can't get an exception here, but just in order to enforce
4702 // the checking of inputs in the runtime calls we check here.
4703 if (!maybe_element->ToObject(&element)) return maybe_element;
4704 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4706 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4707 break;
4708 }
4709
lrn@chromium.org303ada72010-10-27 09:33:13 +00004710 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 }
4716
lrn@chromium.org303ada72010-10-27 09:33:13 +00004717 Object* object = NULL;
4718 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 String* result = String::cast(object);
4720 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004721 Object* element;
4722 { MaybeObject* maybe_element = codes->GetElement(i);
4723 if (!maybe_element->ToObject(&element)) return maybe_element;
4724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004726 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 }
4728 return result;
4729}
4730
4731
4732// kNotEscaped is generated by the following:
4733//
4734// #!/bin/perl
4735// for (my $i = 0; $i < 256; $i++) {
4736// print "\n" if $i % 16 == 0;
4737// my $c = chr($i);
4738// my $escaped = 1;
4739// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4740// print $escaped ? "0, " : "1, ";
4741// }
4742
4743
4744static bool IsNotEscaped(uint16_t character) {
4745 // Only for 8 bit characters, the rest are always escaped (in a different way)
4746 ASSERT(character < 256);
4747 static const char kNotEscaped[256] = {
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4750 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4753 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4754 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4755 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4764 };
4765 return kNotEscaped[character] != 0;
4766}
4767
4768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004769RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 const char hex_chars[] = "0123456789ABCDEF";
4771 NoHandleAllocation ha;
4772 ASSERT(args.length() == 1);
4773 CONVERT_CHECKED(String, source, args[0]);
4774
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004775 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776
4777 int escaped_length = 0;
4778 int length = source->length();
4779 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004780 Access<StringInputBuffer> buffer(
4781 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782 buffer->Reset(source);
4783 while (buffer->has_more()) {
4784 uint16_t character = buffer->GetNext();
4785 if (character >= 256) {
4786 escaped_length += 6;
4787 } else if (IsNotEscaped(character)) {
4788 escaped_length++;
4789 } else {
4790 escaped_length += 3;
4791 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004792 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004793 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004794 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 return Failure::OutOfMemoryException();
4797 }
4798 }
4799 }
4800 // No length change implies no change. Return original string if no change.
4801 if (escaped_length == length) {
4802 return source;
4803 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004804 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004805 { MaybeObject* maybe_o =
4806 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004807 if (!maybe_o->ToObject(&o)) return maybe_o;
4808 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004809 String* destination = String::cast(o);
4810 int dest_position = 0;
4811
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004812 Access<StringInputBuffer> buffer(
4813 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 buffer->Rewind();
4815 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004816 uint16_t chr = buffer->GetNext();
4817 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004818 destination->Set(dest_position, '%');
4819 destination->Set(dest_position+1, 'u');
4820 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4821 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4822 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4823 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004825 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004826 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 dest_position++;
4828 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004829 destination->Set(dest_position, '%');
4830 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4831 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 dest_position += 3;
4833 }
4834 }
4835 return destination;
4836}
4837
4838
4839static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4840 static const signed char kHexValue['g'] = {
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4844 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4845 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4847 -1, 10, 11, 12, 13, 14, 15 };
4848
4849 if (character1 > 'f') return -1;
4850 int hi = kHexValue[character1];
4851 if (hi == -1) return -1;
4852 if (character2 > 'f') return -1;
4853 int lo = kHexValue[character2];
4854 if (lo == -1) return -1;
4855 return (hi << 4) + lo;
4856}
4857
4858
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004860 int i,
4861 int length,
4862 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004863 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004864 int32_t hi = 0;
4865 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 if (character == '%' &&
4867 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004868 source->Get(i + 1) == 'u' &&
4869 (hi = TwoDigitHex(source->Get(i + 2),
4870 source->Get(i + 3))) != -1 &&
4871 (lo = TwoDigitHex(source->Get(i + 4),
4872 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 *step = 6;
4874 return (hi << 8) + lo;
4875 } else if (character == '%' &&
4876 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004877 (lo = TwoDigitHex(source->Get(i + 1),
4878 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879 *step = 3;
4880 return lo;
4881 } else {
4882 *step = 1;
4883 return character;
4884 }
4885}
4886
4887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004888RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889 NoHandleAllocation ha;
4890 ASSERT(args.length() == 1);
4891 CONVERT_CHECKED(String, source, args[0]);
4892
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004893 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894
4895 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004896 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897
4898 int unescaped_length = 0;
4899 for (int i = 0; i < length; unescaped_length++) {
4900 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004901 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004903 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004904 i += step;
4905 }
4906
4907 // No length change implies no change. Return original string if no change.
4908 if (unescaped_length == length)
4909 return source;
4910
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004912 { MaybeObject* maybe_o =
4913 ascii ?
4914 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4915 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 if (!maybe_o->ToObject(&o)) return maybe_o;
4917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004918 String* destination = String::cast(o);
4919
4920 int dest_position = 0;
4921 for (int i = 0; i < length; dest_position++) {
4922 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004923 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 i += step;
4925 }
4926 return destination;
4927}
4928
4929
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004930static const unsigned int kQuoteTableLength = 128u;
4931
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004932static const int kJsonQuotesCharactersPerEntry = 8;
4933static const char* const JsonQuotes =
4934 "\\u0000 \\u0001 \\u0002 \\u0003 "
4935 "\\u0004 \\u0005 \\u0006 \\u0007 "
4936 "\\b \\t \\n \\u000b "
4937 "\\f \\r \\u000e \\u000f "
4938 "\\u0010 \\u0011 \\u0012 \\u0013 "
4939 "\\u0014 \\u0015 \\u0016 \\u0017 "
4940 "\\u0018 \\u0019 \\u001a \\u001b "
4941 "\\u001c \\u001d \\u001e \\u001f "
4942 " ! \\\" # "
4943 "$ % & ' "
4944 "( ) * + "
4945 ", - . / "
4946 "0 1 2 3 "
4947 "4 5 6 7 "
4948 "8 9 : ; "
4949 "< = > ? "
4950 "@ A B C "
4951 "D E F G "
4952 "H I J K "
4953 "L M N O "
4954 "P Q R S "
4955 "T U V W "
4956 "X Y Z [ "
4957 "\\\\ ] ^ _ "
4958 "` a b c "
4959 "d e f g "
4960 "h i j k "
4961 "l m n o "
4962 "p q r s "
4963 "t u v w "
4964 "x y z { "
4965 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004966
4967
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004968// For a string that is less than 32k characters it should always be
4969// possible to allocate it in new space.
4970static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4971
4972
4973// Doing JSON quoting cannot make the string more than this many times larger.
4974static const int kJsonQuoteWorstCaseBlowup = 6;
4975
4976
4977// Covers the entire ASCII range (all other characters are unchanged by JSON
4978// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004979static const byte JsonQuoteLengths[kQuoteTableLength] = {
4980 6, 6, 6, 6, 6, 6, 6, 6,
4981 2, 2, 2, 6, 2, 2, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 6, 6, 6, 6, 6, 6, 6, 6,
4984 1, 1, 2, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 1, 1, 1, 1,
4991 1, 1, 1, 1, 2, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995 1, 1, 1, 1, 1, 1, 1, 1,
4996};
4997
4998
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004999template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005001
5002
5003template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5005 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005006}
5007
5008
5009template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5011 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005012}
5013
5014
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005015template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5017 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005018 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005019 const Char* read_cursor = characters.start();
5020 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005021 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005022 int quoted_length = kSpaceForQuotes;
5023 while (read_cursor < end) {
5024 Char c = *(read_cursor++);
5025 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5026 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005028 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005029 }
5030 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5032 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005033 Object* new_object;
5034 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005035 return new_alloc;
5036 }
5037 StringType* new_string = StringType::cast(new_object);
5038
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005039 Char* write_cursor = reinterpret_cast<Char*>(
5040 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005041 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005042 *(write_cursor++) = '"';
5043
5044 read_cursor = characters.start();
5045 while (read_cursor < end) {
5046 Char c = *(read_cursor++);
5047 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5048 *(write_cursor++) = c;
5049 } else {
5050 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5051 const char* replacement = JsonQuotes +
5052 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5053 for (int i = 0; i < len; i++) {
5054 *write_cursor++ = *replacement++;
5055 }
5056 }
5057 }
5058 *(write_cursor++) = '"';
5059 return new_string;
5060}
5061
5062
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005063template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064static MaybeObject* QuoteJsonString(Isolate* isolate,
5065 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005066 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005068 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005069 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5070 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005072 }
5073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5075 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005076 Object* new_object;
5077 if (!new_alloc->ToObject(&new_object)) {
5078 return new_alloc;
5079 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005080 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005081 // Even if our string is small enough to fit in new space we still have to
5082 // handle it being allocated in old space as may happen in the third
5083 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5084 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005086 }
5087 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005089
5090 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5091 Char* write_cursor = reinterpret_cast<Char*>(
5092 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005093 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005094 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005095
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005096 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005097 const Char* end = read_cursor + length;
5098 while (read_cursor < end) {
5099 Char c = *(read_cursor++);
5100 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5101 *(write_cursor++) = c;
5102 } else {
5103 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5104 const char* replacement = JsonQuotes +
5105 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5106 write_cursor[0] = replacement[0];
5107 if (len > 1) {
5108 write_cursor[1] = replacement[1];
5109 if (len > 2) {
5110 ASSERT(len == 6);
5111 write_cursor[2] = replacement[2];
5112 write_cursor[3] = replacement[3];
5113 write_cursor[4] = replacement[4];
5114 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005115 }
5116 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005117 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005118 }
5119 }
5120 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005121
5122 int final_length = static_cast<int>(
5123 write_cursor - reinterpret_cast<Char*>(
5124 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005125 isolate->heap()->new_space()->
5126 template ShrinkStringAtAllocationBoundary<StringType>(
5127 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005128 return new_string;
5129}
5130
5131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005132RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005133 NoHandleAllocation ha;
5134 CONVERT_CHECKED(String, str, args[0]);
5135 if (!str->IsFlat()) {
5136 MaybeObject* try_flatten = str->TryFlatten();
5137 Object* flat;
5138 if (!try_flatten->ToObject(&flat)) {
5139 return try_flatten;
5140 }
5141 str = String::cast(flat);
5142 ASSERT(str->IsFlat());
5143 }
5144 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005145 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5146 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5149 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005150 }
5151}
5152
5153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005154RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005155 NoHandleAllocation ha;
5156 CONVERT_CHECKED(String, str, args[0]);
5157 if (!str->IsFlat()) {
5158 MaybeObject* try_flatten = str->TryFlatten();
5159 Object* flat;
5160 if (!try_flatten->ToObject(&flat)) {
5161 return try_flatten;
5162 }
5163 str = String::cast(flat);
5164 ASSERT(str->IsFlat());
5165 }
5166 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005167 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5168 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005169 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5171 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005172 }
5173}
5174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005175RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 NoHandleAllocation ha;
5177
5178 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005179 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005181 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182
lrn@chromium.org25156de2010-04-06 13:10:27 +00005183 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005184 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005185 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186}
5187
5188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005189RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 NoHandleAllocation ha;
5191 CONVERT_CHECKED(String, str, args[0]);
5192
5193 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005194 double value = StringToDouble(isolate->unicode_cache(),
5195 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196
5197 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005198 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199}
5200
5201
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005203MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005205 String* s,
5206 int length,
5207 int input_string_length,
5208 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005209 // We try this twice, once with the assumption that the result is no longer
5210 // than the input and, if that assumption breaks, again with the exact
5211 // length. This may not be pretty, but it is nicer than what was here before
5212 // and I hereby claim my vaffel-is.
5213 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 // Allocate the resulting string.
5215 //
5216 // NOTE: This assumes that the upper/lower case of an ascii
5217 // character is also ascii. This is currently the case, but it
5218 // might break in the future if we implement more context and locale
5219 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005220 Object* o;
5221 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 ? isolate->heap()->AllocateRawAsciiString(length)
5223 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005224 if (!maybe_o->ToObject(&o)) return maybe_o;
5225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 String* result = String::cast(o);
5227 bool has_changed_character = false;
5228
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 // Convert all characters to upper case, assuming that they will fit
5230 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 Access<StringInputBuffer> buffer(
5232 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005234 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 // We can assume that the string is not empty
5236 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005237 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005238 bool has_next = buffer->has_more();
5239 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 int char_length = mapping->get(current, next, chars);
5241 if (char_length == 0) {
5242 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005243 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005244 i++;
5245 } else if (char_length == 1) {
5246 // Common case: converting the letter resulted in one character.
5247 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005248 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249 has_changed_character = true;
5250 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005251 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 // We've assumed that the result would be as long as the
5253 // input but here is a character that converts to several
5254 // characters. No matter, we calculate the exact length
5255 // of the result and try the whole thing again.
5256 //
5257 // Note that this leaves room for optimization. We could just
5258 // memcpy what we already have to the result string. Also,
5259 // the result string is the last object allocated we could
5260 // "realloc" it and probably, in the vast majority of cases,
5261 // extend the existing string to be able to hold the full
5262 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005263 int next_length = 0;
5264 if (has_next) {
5265 next_length = mapping->get(next, 0, chars);
5266 if (next_length == 0) next_length = 1;
5267 }
5268 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 while (buffer->has_more()) {
5270 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005271 // NOTE: we use 0 as the next character here because, while
5272 // the next character may affect what a character converts to,
5273 // it does not in any case affect the length of what it convert
5274 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275 int char_length = mapping->get(current, 0, chars);
5276 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005277 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005278 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005279 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005280 return Failure::OutOfMemoryException();
5281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005283 // Try again with the real length.
5284 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 } else {
5286 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005287 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 i++;
5289 }
5290 has_changed_character = true;
5291 }
5292 current = next;
5293 }
5294 if (has_changed_character) {
5295 return result;
5296 } else {
5297 // If we didn't actually change anything in doing the conversion
5298 // we simple return the result and let the converted string
5299 // become garbage; there is no reason to keep two identical strings
5300 // alive.
5301 return s;
5302 }
5303}
5304
5305
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005306namespace {
5307
lrn@chromium.org303ada72010-10-27 09:33:13 +00005308static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5309
5310
5311// Given a word and two range boundaries returns a word with high bit
5312// set in every byte iff the corresponding input byte was strictly in
5313// the range (m, n). All the other bits in the result are cleared.
5314// This function is only useful when it can be inlined and the
5315// boundaries are statically known.
5316// Requires: all bytes in the input word and the boundaries must be
5317// ascii (less than 0x7F).
5318static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5319 // Every byte in an ascii string is less than or equal to 0x7F.
5320 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5321 // Use strict inequalities since in edge cases the function could be
5322 // further simplified.
5323 ASSERT(0 < m && m < n && n < 0x7F);
5324 // Has high bit set in every w byte less than n.
5325 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5326 // Has high bit set in every w byte greater than m.
5327 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5328 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5329}
5330
5331
5332enum AsciiCaseConversion {
5333 ASCII_TO_LOWER,
5334 ASCII_TO_UPPER
5335};
5336
5337
5338template <AsciiCaseConversion dir>
5339struct FastAsciiConverter {
5340 static bool Convert(char* dst, char* src, int length) {
5341#ifdef DEBUG
5342 char* saved_dst = dst;
5343 char* saved_src = src;
5344#endif
5345 // We rely on the distance between upper and lower case letters
5346 // being a known power of 2.
5347 ASSERT('a' - 'A' == (1 << 5));
5348 // Boundaries for the range of input characters than require conversion.
5349 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5350 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5351 bool changed = false;
5352 char* const limit = src + length;
5353#ifdef V8_HOST_CAN_READ_UNALIGNED
5354 // Process the prefix of the input that requires no conversion one
5355 // (machine) word at a time.
5356 while (src <= limit - sizeof(uintptr_t)) {
5357 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5358 if (AsciiRangeMask(w, lo, hi) != 0) {
5359 changed = true;
5360 break;
5361 }
5362 *reinterpret_cast<uintptr_t*>(dst) = w;
5363 src += sizeof(uintptr_t);
5364 dst += sizeof(uintptr_t);
5365 }
5366 // Process the remainder of the input performing conversion when
5367 // required one word at a time.
5368 while (src <= limit - sizeof(uintptr_t)) {
5369 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5370 uintptr_t m = AsciiRangeMask(w, lo, hi);
5371 // The mask has high (7th) bit set in every byte that needs
5372 // conversion and we know that the distance between cases is
5373 // 1 << 5.
5374 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5375 src += sizeof(uintptr_t);
5376 dst += sizeof(uintptr_t);
5377 }
5378#endif
5379 // Process the last few bytes of the input (or the whole input if
5380 // unaligned access is not supported).
5381 while (src < limit) {
5382 char c = *src;
5383 if (lo < c && c < hi) {
5384 c ^= (1 << 5);
5385 changed = true;
5386 }
5387 *dst = c;
5388 ++src;
5389 ++dst;
5390 }
5391#ifdef DEBUG
5392 CheckConvert(saved_dst, saved_src, length, changed);
5393#endif
5394 return changed;
5395 }
5396
5397#ifdef DEBUG
5398 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5399 bool expected_changed = false;
5400 for (int i = 0; i < length; i++) {
5401 if (dst[i] == src[i]) continue;
5402 expected_changed = true;
5403 if (dir == ASCII_TO_LOWER) {
5404 ASSERT('A' <= src[i] && src[i] <= 'Z');
5405 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5406 } else {
5407 ASSERT(dir == ASCII_TO_UPPER);
5408 ASSERT('a' <= src[i] && src[i] <= 'z');
5409 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5410 }
5411 }
5412 ASSERT(expected_changed == changed);
5413 }
5414#endif
5415};
5416
5417
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005418struct ToLowerTraits {
5419 typedef unibrow::ToLowercase UnibrowConverter;
5420
lrn@chromium.org303ada72010-10-27 09:33:13 +00005421 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005422};
5423
5424
5425struct ToUpperTraits {
5426 typedef unibrow::ToUppercase UnibrowConverter;
5427
lrn@chromium.org303ada72010-10-27 09:33:13 +00005428 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005429};
5430
5431} // namespace
5432
5433
5434template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005435MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005436 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005438 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005440 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005441 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005442
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005443 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005444 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005445 if (length == 0) return s;
5446
5447 // Simpler handling of ascii strings.
5448 //
5449 // NOTE: This assumes that the upper/lower case of an ascii
5450 // character is also ascii. This is currently the case, but it
5451 // might break in the future if we implement more context and locale
5452 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005453 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005454 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005455 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005456 if (!maybe_o->ToObject(&o)) return maybe_o;
5457 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005459 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005460 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005461 return has_changed_character ? result : s;
5462 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463
lrn@chromium.org303ada72010-10-27 09:33:13 +00005464 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005465 { MaybeObject* maybe_answer =
5466 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005467 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005469 if (answer->IsSmi()) {
5470 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005472 ConvertCaseHelper(isolate,
5473 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005474 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5475 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005477 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478}
5479
5480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005481RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005482 return ConvertCase<ToLowerTraits>(
5483 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005484}
5485
5486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005487RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005488 return ConvertCase<ToUpperTraits>(
5489 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005490}
5491
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005492
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005493static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5494 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5495}
5496
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005498RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005499 NoHandleAllocation ha;
5500 ASSERT(args.length() == 3);
5501
5502 CONVERT_CHECKED(String, s, args[0]);
5503 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5504 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5505
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005506 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005507 int length = s->length();
5508
5509 int left = 0;
5510 if (trimLeft) {
5511 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5512 left++;
5513 }
5514 }
5515
5516 int right = length;
5517 if (trimRight) {
5518 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5519 right--;
5520 }
5521 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005522 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005523}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005525
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005526template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005527void FindStringIndices(Isolate* isolate,
5528 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005529 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005530 ZoneList<int>* indices,
5531 unsigned int limit) {
5532 ASSERT(limit > 0);
5533 // Collect indices of pattern in subject, and the end-of-string index.
5534 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005535 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005536 int pattern_length = pattern.length();
5537 int index = 0;
5538 while (limit > 0) {
5539 index = search.Search(subject, index);
5540 if (index < 0) return;
5541 indices->Add(index);
5542 index += pattern_length;
5543 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005544 }
5545}
5546
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005548RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005549 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005550 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005551 CONVERT_ARG_CHECKED(String, subject, 0);
5552 CONVERT_ARG_CHECKED(String, pattern, 1);
5553 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5554
5555 int subject_length = subject->length();
5556 int pattern_length = pattern->length();
5557 RUNTIME_ASSERT(pattern_length > 0);
5558
5559 // The limit can be very large (0xffffffffu), but since the pattern
5560 // isn't empty, we can never create more parts than ~half the length
5561 // of the subject.
5562
5563 if (!subject->IsFlat()) FlattenString(subject);
5564
5565 static const int kMaxInitialListCapacity = 16;
5566
5567 ZoneScope scope(DELETE_ON_EXIT);
5568
5569 // Find (up to limit) indices of separator and end-of-string in subject
5570 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5571 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005572 if (!pattern->IsFlat()) FlattenString(pattern);
5573
5574 // No allocation block.
5575 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005576 AssertNoAllocation nogc;
5577 if (subject->IsAsciiRepresentation()) {
5578 Vector<const char> subject_vector = subject->ToAsciiVector();
5579 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005580 FindStringIndices(isolate,
5581 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005582 pattern->ToAsciiVector(),
5583 &indices,
5584 limit);
5585 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005586 FindStringIndices(isolate,
5587 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005588 pattern->ToUC16Vector(),
5589 &indices,
5590 limit);
5591 }
5592 } else {
5593 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5594 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005595 FindStringIndices(isolate,
5596 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005597 pattern->ToAsciiVector(),
5598 &indices,
5599 limit);
5600 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005601 FindStringIndices(isolate,
5602 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005603 pattern->ToUC16Vector(),
5604 &indices,
5605 limit);
5606 }
5607 }
5608 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005609
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005610 if (static_cast<uint32_t>(indices.length()) < limit) {
5611 indices.Add(subject_length);
5612 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005613
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005614 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005615
5616 // Create JSArray of substrings separated by separator.
5617 int part_count = indices.length();
5618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005620 result->set_length(Smi::FromInt(part_count));
5621
5622 ASSERT(result->HasFastElements());
5623
5624 if (part_count == 1 && indices.at(0) == subject_length) {
5625 FixedArray::cast(result->elements())->set(0, *subject);
5626 return *result;
5627 }
5628
5629 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5630 int part_start = 0;
5631 for (int i = 0; i < part_count; i++) {
5632 HandleScope local_loop_handle;
5633 int part_end = indices.at(i);
5634 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005636 elements->set(i, *substring);
5637 part_start = part_end + pattern_length;
5638 }
5639
5640 return *result;
5641}
5642
5643
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005644// Copies ascii characters to the given fixed array looking up
5645// one-char strings in the cache. Gives up on the first char that is
5646// not in the cache and fills the remainder with smi zeros. Returns
5647// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005648static int CopyCachedAsciiCharsToArray(Heap* heap,
5649 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005650 FixedArray* elements,
5651 int length) {
5652 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005653 FixedArray* ascii_cache = heap->single_character_string_cache();
5654 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005655 int i;
5656 for (i = 0; i < length; ++i) {
5657 Object* value = ascii_cache->get(chars[i]);
5658 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005659 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005660 elements->set(i, value, SKIP_WRITE_BARRIER);
5661 }
5662 if (i < length) {
5663 ASSERT(Smi::FromInt(0) == 0);
5664 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5665 }
5666#ifdef DEBUG
5667 for (int j = 0; j < length; ++j) {
5668 Object* element = elements->get(j);
5669 ASSERT(element == Smi::FromInt(0) ||
5670 (element->IsString() && String::cast(element)->LooksValid()));
5671 }
5672#endif
5673 return i;
5674}
5675
5676
5677// Converts a String to JSArray.
5678// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005679RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005680 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005681 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005683 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684
5685 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005686 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005687
5688 Handle<FixedArray> elements;
5689 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005690 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005691 { MaybeObject* maybe_obj =
5692 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005693 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5694 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005696
5697 Vector<const char> chars = s->ToAsciiVector();
5698 // Note, this will initialize all elements (not only the prefix)
5699 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005700 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5701 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005702 *elements,
5703 length);
5704
5705 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005706 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5707 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708 }
5709 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005712 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5713 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005714 }
5715 }
5716
5717#ifdef DEBUG
5718 for (int i = 0; i < length; ++i) {
5719 ASSERT(String::cast(elements->get(i))->length() == 1);
5720 }
5721#endif
5722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005723 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005724}
5725
5726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005727RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005728 NoHandleAllocation ha;
5729 ASSERT(args.length() == 1);
5730 CONVERT_CHECKED(String, value, args[0]);
5731 return value->ToObject();
5732}
5733
5734
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005735bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005736 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005737 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005738 return char_length == 0;
5739}
5740
5741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005742RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005743 NoHandleAllocation ha;
5744 ASSERT(args.length() == 1);
5745
5746 Object* number = args[0];
5747 RUNTIME_ASSERT(number->IsNumber());
5748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005749 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005750}
5751
5752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005753RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005754 NoHandleAllocation ha;
5755 ASSERT(args.length() == 1);
5756
5757 Object* number = args[0];
5758 RUNTIME_ASSERT(number->IsNumber());
5759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005760 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005761}
5762
5763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005764RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005765 NoHandleAllocation ha;
5766 ASSERT(args.length() == 1);
5767
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005768 CONVERT_DOUBLE_CHECKED(number, args[0]);
5769
5770 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5771 if (number > 0 && number <= Smi::kMaxValue) {
5772 return Smi::FromInt(static_cast<int>(number));
5773 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005774 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775}
5776
5777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005778RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005779 NoHandleAllocation ha;
5780 ASSERT(args.length() == 1);
5781
5782 CONVERT_DOUBLE_CHECKED(number, args[0]);
5783
5784 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5785 if (number > 0 && number <= Smi::kMaxValue) {
5786 return Smi::FromInt(static_cast<int>(number));
5787 }
5788
5789 double double_value = DoubleToInteger(number);
5790 // Map both -0 and +0 to +0.
5791 if (double_value == 0) double_value = 0;
5792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005794}
5795
5796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005797RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005798 NoHandleAllocation ha;
5799 ASSERT(args.length() == 1);
5800
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005801 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005802 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803}
5804
5805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005806RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005807 NoHandleAllocation ha;
5808 ASSERT(args.length() == 1);
5809
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005810 CONVERT_DOUBLE_CHECKED(number, args[0]);
5811
5812 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5813 if (number > 0 && number <= Smi::kMaxValue) {
5814 return Smi::FromInt(static_cast<int>(number));
5815 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005817}
5818
5819
ager@chromium.org870a0b62008-11-04 11:43:05 +00005820// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5821// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005822RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005823 NoHandleAllocation ha;
5824 ASSERT(args.length() == 1);
5825
5826 Object* obj = args[0];
5827 if (obj->IsSmi()) {
5828 return obj;
5829 }
5830 if (obj->IsHeapNumber()) {
5831 double value = HeapNumber::cast(obj)->value();
5832 int int_value = FastD2I(value);
5833 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5834 return Smi::FromInt(int_value);
5835 }
5836 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005837 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005838}
5839
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005841RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005842 NoHandleAllocation ha;
5843 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005845}
5846
5847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005848RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005849 NoHandleAllocation ha;
5850 ASSERT(args.length() == 2);
5851
5852 CONVERT_DOUBLE_CHECKED(x, args[0]);
5853 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855}
5856
5857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005858RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005859 NoHandleAllocation ha;
5860 ASSERT(args.length() == 2);
5861
5862 CONVERT_DOUBLE_CHECKED(x, args[0]);
5863 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005864 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005865}
5866
5867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005868RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005869 NoHandleAllocation ha;
5870 ASSERT(args.length() == 2);
5871
5872 CONVERT_DOUBLE_CHECKED(x, args[0]);
5873 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005875}
5876
5877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005878RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005879 NoHandleAllocation ha;
5880 ASSERT(args.length() == 1);
5881
5882 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005883 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884}
5885
5886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005887RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005888 NoHandleAllocation ha;
5889 ASSERT(args.length() == 0);
5890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005891 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005892}
5893
5894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005895RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896 NoHandleAllocation ha;
5897 ASSERT(args.length() == 2);
5898
5899 CONVERT_DOUBLE_CHECKED(x, args[0]);
5900 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005901 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902}
5903
5904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005905RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 2);
5908
5909 CONVERT_DOUBLE_CHECKED(x, args[0]);
5910 CONVERT_DOUBLE_CHECKED(y, args[1]);
5911
ager@chromium.org3811b432009-10-28 14:53:37 +00005912 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005913 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915}
5916
5917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005918RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005919 NoHandleAllocation ha;
5920 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 CONVERT_CHECKED(String, str1, args[0]);
5922 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 isolate->counters()->string_add_runtime()->Increment();
5924 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925}
5926
5927
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005928template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005929static inline void StringBuilderConcatHelper(String* special,
5930 sinkchar* sink,
5931 FixedArray* fixed_array,
5932 int array_length) {
5933 int position = 0;
5934 for (int i = 0; i < array_length; i++) {
5935 Object* element = fixed_array->get(i);
5936 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005937 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005938 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005939 int pos;
5940 int len;
5941 if (encoded_slice > 0) {
5942 // Position and length encoded in one smi.
5943 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5944 len = StringBuilderSubstringLength::decode(encoded_slice);
5945 } else {
5946 // Position and length encoded in two smis.
5947 Object* obj = fixed_array->get(++i);
5948 ASSERT(obj->IsSmi());
5949 pos = Smi::cast(obj)->value();
5950 len = -encoded_slice;
5951 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005952 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005953 sink + position,
5954 pos,
5955 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005956 position += len;
5957 } else {
5958 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005959 int element_length = string->length();
5960 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005961 position += element_length;
5962 }
5963 }
5964}
5965
5966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005969 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005971 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005972 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005973 return Failure::OutOfMemoryException();
5974 }
5975 int array_length = Smi::cast(args[1])->value();
5976 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005977
5978 // This assumption is used by the slice encoding in one or two smis.
5979 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5980
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005981 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005983 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 }
5985 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005986 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989
5990 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005991 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 } else if (array_length == 1) {
5993 Object* first = fixed_array->get(0);
5994 if (first->IsString()) return first;
5995 }
5996
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005997 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 int position = 0;
5999 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006000 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 Object* elt = fixed_array->get(i);
6002 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006003 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006004 int smi_value = Smi::cast(elt)->value();
6005 int pos;
6006 int len;
6007 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006008 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006009 pos = StringBuilderSubstringPosition::decode(smi_value);
6010 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006011 } else {
6012 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006013 len = -smi_value;
6014 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006015 i++;
6016 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006018 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006019 Object* next_smi = fixed_array->get(i);
6020 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006022 }
6023 pos = Smi::cast(next_smi)->value();
6024 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006028 ASSERT(pos >= 0);
6029 ASSERT(len >= 0);
6030 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006031 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006032 }
6033 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 } else if (elt->IsString()) {
6035 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006036 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006037 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006038 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006040 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006042 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006044 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006045 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006046 return Failure::OutOfMemoryException();
6047 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006048 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 }
6050
6051 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006052 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006055 { MaybeObject* maybe_object =
6056 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006057 if (!maybe_object->ToObject(&object)) return maybe_object;
6058 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006059 SeqAsciiString* answer = SeqAsciiString::cast(object);
6060 StringBuilderConcatHelper(special,
6061 answer->GetChars(),
6062 fixed_array,
6063 array_length);
6064 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006066 { MaybeObject* maybe_object =
6067 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006068 if (!maybe_object->ToObject(&object)) return maybe_object;
6069 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006070 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6071 StringBuilderConcatHelper(special,
6072 answer->GetChars(),
6073 fixed_array,
6074 array_length);
6075 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077}
6078
6079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006080RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006081 NoHandleAllocation ha;
6082 ASSERT(args.length() == 3);
6083 CONVERT_CHECKED(JSArray, array, args[0]);
6084 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006086 return Failure::OutOfMemoryException();
6087 }
6088 int array_length = Smi::cast(args[1])->value();
6089 CONVERT_CHECKED(String, separator, args[2]);
6090
6091 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006093 }
6094 FixedArray* fixed_array = FixedArray::cast(array->elements());
6095 if (fixed_array->length() < array_length) {
6096 array_length = fixed_array->length();
6097 }
6098
6099 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006100 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006101 } else if (array_length == 1) {
6102 Object* first = fixed_array->get(0);
6103 if (first->IsString()) return first;
6104 }
6105
6106 int separator_length = separator->length();
6107 int max_nof_separators =
6108 (String::kMaxLength + separator_length - 1) / separator_length;
6109 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006111 return Failure::OutOfMemoryException();
6112 }
6113 int length = (array_length - 1) * separator_length;
6114 for (int i = 0; i < array_length; i++) {
6115 Object* element_obj = fixed_array->get(i);
6116 if (!element_obj->IsString()) {
6117 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006118 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006119 }
6120 String* element = String::cast(element_obj);
6121 int increment = element->length();
6122 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006123 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006124 return Failure::OutOfMemoryException();
6125 }
6126 length += increment;
6127 }
6128
6129 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006130 { MaybeObject* maybe_object =
6131 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006132 if (!maybe_object->ToObject(&object)) return maybe_object;
6133 }
6134 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6135
6136 uc16* sink = answer->GetChars();
6137#ifdef DEBUG
6138 uc16* end = sink + length;
6139#endif
6140
6141 String* first = String::cast(fixed_array->get(0));
6142 int first_length = first->length();
6143 String::WriteToFlat(first, sink, 0, first_length);
6144 sink += first_length;
6145
6146 for (int i = 1; i < array_length; i++) {
6147 ASSERT(sink + separator_length <= end);
6148 String::WriteToFlat(separator, sink, 0, separator_length);
6149 sink += separator_length;
6150
6151 String* element = String::cast(fixed_array->get(i));
6152 int element_length = element->length();
6153 ASSERT(sink + element_length <= end);
6154 String::WriteToFlat(element, sink, 0, element_length);
6155 sink += element_length;
6156 }
6157 ASSERT(sink == end);
6158
6159 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6160 return answer;
6161}
6162
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006163template <typename Char>
6164static void JoinSparseArrayWithSeparator(FixedArray* elements,
6165 int elements_length,
6166 uint32_t array_length,
6167 String* separator,
6168 Vector<Char> buffer) {
6169 int previous_separator_position = 0;
6170 int separator_length = separator->length();
6171 int cursor = 0;
6172 for (int i = 0; i < elements_length; i += 2) {
6173 int position = NumberToInt32(elements->get(i));
6174 String* string = String::cast(elements->get(i + 1));
6175 int string_length = string->length();
6176 if (string->length() > 0) {
6177 while (previous_separator_position < position) {
6178 String::WriteToFlat<Char>(separator, &buffer[cursor],
6179 0, separator_length);
6180 cursor += separator_length;
6181 previous_separator_position++;
6182 }
6183 String::WriteToFlat<Char>(string, &buffer[cursor],
6184 0, string_length);
6185 cursor += string->length();
6186 }
6187 }
6188 if (separator_length > 0) {
6189 // Array length must be representable as a signed 32-bit number,
6190 // otherwise the total string length would have been too large.
6191 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6192 int last_array_index = static_cast<int>(array_length - 1);
6193 while (previous_separator_position < last_array_index) {
6194 String::WriteToFlat<Char>(separator, &buffer[cursor],
6195 0, separator_length);
6196 cursor += separator_length;
6197 previous_separator_position++;
6198 }
6199 }
6200 ASSERT(cursor <= buffer.length());
6201}
6202
6203
6204RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6205 NoHandleAllocation ha;
6206 ASSERT(args.length() == 3);
6207 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6208 RUNTIME_ASSERT(elements_array->HasFastElements());
6209 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6210 CONVERT_CHECKED(String, separator, args[2]);
6211 // elements_array is fast-mode JSarray of alternating positions
6212 // (increasing order) and strings.
6213 // array_length is length of original array (used to add separators);
6214 // separator is string to put between elements. Assumed to be non-empty.
6215
6216 // Find total length of join result.
6217 int string_length = 0;
6218 bool is_ascii = true;
6219 int max_string_length = SeqAsciiString::kMaxLength;
6220 bool overflow = false;
6221 CONVERT_NUMBER_CHECKED(int, elements_length,
6222 Int32, elements_array->length());
6223 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6224 FixedArray* elements = FixedArray::cast(elements_array->elements());
6225 for (int i = 0; i < elements_length; i += 2) {
6226 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6227 CONVERT_CHECKED(String, string, elements->get(i + 1));
6228 int length = string->length();
6229 if (is_ascii && !string->IsAsciiRepresentation()) {
6230 is_ascii = false;
6231 max_string_length = SeqTwoByteString::kMaxLength;
6232 }
6233 if (length > max_string_length ||
6234 max_string_length - length < string_length) {
6235 overflow = true;
6236 break;
6237 }
6238 string_length += length;
6239 }
6240 int separator_length = separator->length();
6241 if (!overflow && separator_length > 0) {
6242 if (array_length <= 0x7fffffffu) {
6243 int separator_count = static_cast<int>(array_length) - 1;
6244 int remaining_length = max_string_length - string_length;
6245 if ((remaining_length / separator_length) >= separator_count) {
6246 string_length += separator_length * (array_length - 1);
6247 } else {
6248 // Not room for the separators within the maximal string length.
6249 overflow = true;
6250 }
6251 } else {
6252 // Nonempty separator and at least 2^31-1 separators necessary
6253 // means that the string is too large to create.
6254 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6255 overflow = true;
6256 }
6257 }
6258 if (overflow) {
6259 // Throw OutOfMemory exception for creating too large a string.
6260 V8::FatalProcessOutOfMemory("Array join result too large.");
6261 }
6262
6263 if (is_ascii) {
6264 MaybeObject* result_allocation =
6265 isolate->heap()->AllocateRawAsciiString(string_length);
6266 if (result_allocation->IsFailure()) return result_allocation;
6267 SeqAsciiString* result_string =
6268 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6269 JoinSparseArrayWithSeparator<char>(elements,
6270 elements_length,
6271 array_length,
6272 separator,
6273 Vector<char>(result_string->GetChars(),
6274 string_length));
6275 return result_string;
6276 } else {
6277 MaybeObject* result_allocation =
6278 isolate->heap()->AllocateRawTwoByteString(string_length);
6279 if (result_allocation->IsFailure()) return result_allocation;
6280 SeqTwoByteString* result_string =
6281 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6282 JoinSparseArrayWithSeparator<uc16>(elements,
6283 elements_length,
6284 array_length,
6285 separator,
6286 Vector<uc16>(result_string->GetChars(),
6287 string_length));
6288 return result_string;
6289 }
6290}
6291
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006293RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294 NoHandleAllocation ha;
6295 ASSERT(args.length() == 2);
6296
6297 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6298 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006299 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300}
6301
6302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006303RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006304 NoHandleAllocation ha;
6305 ASSERT(args.length() == 2);
6306
6307 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6308 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310}
6311
6312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006313RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006314 NoHandleAllocation ha;
6315 ASSERT(args.length() == 2);
6316
6317 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6318 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320}
6321
6322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006323RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006324 NoHandleAllocation ha;
6325 ASSERT(args.length() == 1);
6326
6327 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006328 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329}
6330
6331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006332RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 NoHandleAllocation ha;
6334 ASSERT(args.length() == 2);
6335
6336 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6337 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006338 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339}
6340
6341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006342RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343 NoHandleAllocation ha;
6344 ASSERT(args.length() == 2);
6345
6346 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6347 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006348 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006349}
6350
6351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006352RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006353 NoHandleAllocation ha;
6354 ASSERT(args.length() == 2);
6355
6356 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6357 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006358 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006359}
6360
6361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006362RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363 NoHandleAllocation ha;
6364 ASSERT(args.length() == 2);
6365
6366 CONVERT_DOUBLE_CHECKED(x, args[0]);
6367 CONVERT_DOUBLE_CHECKED(y, args[1]);
6368 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6369 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6370 if (x == y) return Smi::FromInt(EQUAL);
6371 Object* result;
6372 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6373 result = Smi::FromInt(EQUAL);
6374 } else {
6375 result = Smi::FromInt(NOT_EQUAL);
6376 }
6377 return result;
6378}
6379
6380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006381RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 NoHandleAllocation ha;
6383 ASSERT(args.length() == 2);
6384
6385 CONVERT_CHECKED(String, x, args[0]);
6386 CONVERT_CHECKED(String, y, args[1]);
6387
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006388 bool not_equal = !x->Equals(y);
6389 // This is slightly convoluted because the value that signifies
6390 // equality is 0 and inequality is 1 so we have to negate the result
6391 // from String::Equals.
6392 ASSERT(not_equal == 0 || not_equal == 1);
6393 STATIC_CHECK(EQUAL == 0);
6394 STATIC_CHECK(NOT_EQUAL == 1);
6395 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006396}
6397
6398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006399RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400 NoHandleAllocation ha;
6401 ASSERT(args.length() == 3);
6402
6403 CONVERT_DOUBLE_CHECKED(x, args[0]);
6404 CONVERT_DOUBLE_CHECKED(y, args[1]);
6405 if (isnan(x) || isnan(y)) return args[2];
6406 if (x == y) return Smi::FromInt(EQUAL);
6407 if (isless(x, y)) return Smi::FromInt(LESS);
6408 return Smi::FromInt(GREATER);
6409}
6410
6411
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006412// Compare two Smis as if they were converted to strings and then
6413// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006414RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006415 NoHandleAllocation ha;
6416 ASSERT(args.length() == 2);
6417
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006418 // Extract the integer values from the Smis.
6419 CONVERT_CHECKED(Smi, x, args[0]);
6420 CONVERT_CHECKED(Smi, y, args[1]);
6421 int x_value = x->value();
6422 int y_value = y->value();
6423
6424 // If the integers are equal so are the string representations.
6425 if (x_value == y_value) return Smi::FromInt(EQUAL);
6426
6427 // If one of the integers are zero the normal integer order is the
6428 // same as the lexicographic order of the string representations.
6429 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6430
ager@chromium.org32912102009-01-16 10:38:43 +00006431 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006432 // smallest because the char code of '-' is less than the char code
6433 // of any digit. Otherwise, we make both values positive.
6434 if (x_value < 0 || y_value < 0) {
6435 if (y_value >= 0) return Smi::FromInt(LESS);
6436 if (x_value >= 0) return Smi::FromInt(GREATER);
6437 x_value = -x_value;
6438 y_value = -y_value;
6439 }
6440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 // Arrays for the individual characters of the two Smis. Smis are
6442 // 31 bit integers and 10 decimal digits are therefore enough.
6443 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6444 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6445 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6446
6447
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006448 // Convert the integers to arrays of their decimal digits.
6449 int x_index = 0;
6450 int y_index = 0;
6451 while (x_value > 0) {
6452 x_elms[x_index++] = x_value % 10;
6453 x_value /= 10;
6454 }
6455 while (y_value > 0) {
6456 y_elms[y_index++] = y_value % 10;
6457 y_value /= 10;
6458 }
6459
6460 // Loop through the arrays of decimal digits finding the first place
6461 // where they differ.
6462 while (--x_index >= 0 && --y_index >= 0) {
6463 int diff = x_elms[x_index] - y_elms[y_index];
6464 if (diff != 0) return Smi::FromInt(diff);
6465 }
6466
6467 // If one array is a suffix of the other array, the longest array is
6468 // the representation of the largest of the Smis in the
6469 // lexicographic ordering.
6470 return Smi::FromInt(x_index - y_index);
6471}
6472
6473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474static Object* StringInputBufferCompare(RuntimeState* state,
6475 String* x,
6476 String* y) {
6477 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6478 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006479 bufx.Reset(x);
6480 bufy.Reset(y);
6481 while (bufx.has_more() && bufy.has_more()) {
6482 int d = bufx.GetNext() - bufy.GetNext();
6483 if (d < 0) return Smi::FromInt(LESS);
6484 else if (d > 0) return Smi::FromInt(GREATER);
6485 }
6486
6487 // x is (non-trivial) prefix of y:
6488 if (bufy.has_more()) return Smi::FromInt(LESS);
6489 // y is prefix of x:
6490 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6491}
6492
6493
6494static Object* FlatStringCompare(String* x, String* y) {
6495 ASSERT(x->IsFlat());
6496 ASSERT(y->IsFlat());
6497 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6498 int prefix_length = x->length();
6499 if (y->length() < prefix_length) {
6500 prefix_length = y->length();
6501 equal_prefix_result = Smi::FromInt(GREATER);
6502 } else if (y->length() > prefix_length) {
6503 equal_prefix_result = Smi::FromInt(LESS);
6504 }
6505 int r;
6506 if (x->IsAsciiRepresentation()) {
6507 Vector<const char> x_chars = x->ToAsciiVector();
6508 if (y->IsAsciiRepresentation()) {
6509 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006510 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006511 } else {
6512 Vector<const uc16> y_chars = y->ToUC16Vector();
6513 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6514 }
6515 } else {
6516 Vector<const uc16> x_chars = x->ToUC16Vector();
6517 if (y->IsAsciiRepresentation()) {
6518 Vector<const char> y_chars = y->ToAsciiVector();
6519 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6520 } else {
6521 Vector<const uc16> y_chars = y->ToUC16Vector();
6522 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6523 }
6524 }
6525 Object* result;
6526 if (r == 0) {
6527 result = equal_prefix_result;
6528 } else {
6529 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6530 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006531 ASSERT(result ==
6532 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006533 return result;
6534}
6535
6536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006537RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006538 NoHandleAllocation ha;
6539 ASSERT(args.length() == 2);
6540
6541 CONVERT_CHECKED(String, x, args[0]);
6542 CONVERT_CHECKED(String, y, args[1]);
6543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 // A few fast case tests before we flatten.
6547 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006548 if (y->length() == 0) {
6549 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006551 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552 return Smi::FromInt(LESS);
6553 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006554
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006555 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006556 if (d < 0) return Smi::FromInt(LESS);
6557 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558
lrn@chromium.org303ada72010-10-27 09:33:13 +00006559 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006560 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006561 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006564 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006567 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006575 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576
6577 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586
6587 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006588 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589}
6590
6591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006592RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 NoHandleAllocation ha;
6594 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596
6597 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006598 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599}
6600
6601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006602static const double kPiDividedBy4 = 0.78539816339744830962;
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609
6610 CONVERT_DOUBLE_CHECKED(x, args[0]);
6611 CONVERT_DOUBLE_CHECKED(y, args[1]);
6612 double result;
6613 if (isinf(x) && isinf(y)) {
6614 // Make sure that the result in case of two infinite arguments
6615 // is a multiple of Pi / 4. The sign of the result is determined
6616 // by the first argument (x) and the sign of the second argument
6617 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 int multiplier = (x < 0) ? -1 : 1;
6619 if (y < 0) multiplier *= 3;
6620 result = multiplier * kPiDividedBy4;
6621 } else {
6622 result = atan2(x, y);
6623 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632
6633 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006634 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006638RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006639 NoHandleAllocation ha;
6640 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642
6643 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006644 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006645}
6646
6647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006648RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649 NoHandleAllocation ha;
6650 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652
6653 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006654 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655}
6656
6657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006658RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659 NoHandleAllocation ha;
6660 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662
6663 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665}
6666
6667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006668RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 NoHandleAllocation ha;
6670 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672
6673 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006674 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675}
6676
6677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006678RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 NoHandleAllocation ha;
6680 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006681 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682
6683 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006684
6685 // If the second argument is a smi, it is much faster to call the
6686 // custom powi() function than the generic pow().
6687 if (args[1]->IsSmi()) {
6688 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006690 }
6691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006693 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694}
6695
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006696// Fast version of Math.pow if we know that y is not an integer and
6697// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006698RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006699 NoHandleAllocation ha;
6700 ASSERT(args.length() == 2);
6701 CONVERT_DOUBLE_CHECKED(x, args[0]);
6702 CONVERT_DOUBLE_CHECKED(y, args[1]);
6703 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006704 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006705 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006707 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006709 }
6710}
6711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006713RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 NoHandleAllocation ha;
6715 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006716 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006718 if (!args[0]->IsHeapNumber()) {
6719 // Must be smi. Return the argument unchanged for all the other types
6720 // to make fuzz-natives test happy.
6721 return args[0];
6722 }
6723
6724 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6725
6726 double value = number->value();
6727 int exponent = number->get_exponent();
6728 int sign = number->get_sign();
6729
danno@chromium.org160a7b02011-04-18 15:51:38 +00006730 if (exponent < -1) {
6731 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6732 if (sign) return isolate->heap()->minus_zero_value();
6733 return Smi::FromInt(0);
6734 }
6735
6736 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6737 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6738 // agument holds for 32-bit smis).
6739 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006740 return Smi::FromInt(static_cast<int>(value + 0.5));
6741 }
6742
6743 // If the magnitude is big enough, there's no place for fraction part. If we
6744 // try to add 0.5 to this number, 1.0 will be added instead.
6745 if (exponent >= 52) {
6746 return number;
6747 }
6748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006749 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006750
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006751 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753}
6754
6755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006756RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 NoHandleAllocation ha;
6758 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006759 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760
6761 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763}
6764
6765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006766RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 NoHandleAllocation ha;
6768 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770
6771 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006772 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773}
6774
6775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006776RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 NoHandleAllocation ha;
6778 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780
6781 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006782 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783}
6784
6785
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006786static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006787 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6788 181, 212, 243, 273, 304, 334};
6789 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6790 182, 213, 244, 274, 305, 335};
6791
6792 year += month / 12;
6793 month %= 12;
6794 if (month < 0) {
6795 year--;
6796 month += 12;
6797 }
6798
6799 ASSERT(month >= 0);
6800 ASSERT(month < 12);
6801
6802 // year_delta is an arbitrary number such that:
6803 // a) year_delta = -1 (mod 400)
6804 // b) year + year_delta > 0 for years in the range defined by
6805 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6806 // Jan 1 1970. This is required so that we don't run into integer
6807 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006808 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006809 // operations.
6810 static const int year_delta = 399999;
6811 static const int base_day = 365 * (1970 + year_delta) +
6812 (1970 + year_delta) / 4 -
6813 (1970 + year_delta) / 100 +
6814 (1970 + year_delta) / 400;
6815
6816 int year1 = year + year_delta;
6817 int day_from_year = 365 * year1 +
6818 year1 / 4 -
6819 year1 / 100 +
6820 year1 / 400 -
6821 base_day;
6822
6823 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006824 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006825 }
6826
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006827 return day_from_year + day_from_month_leap[month] + day - 1;
6828}
6829
6830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006831RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006832 NoHandleAllocation ha;
6833 ASSERT(args.length() == 3);
6834
6835 CONVERT_SMI_CHECKED(year, args[0]);
6836 CONVERT_SMI_CHECKED(month, args[1]);
6837 CONVERT_SMI_CHECKED(date, args[2]);
6838
6839 return Smi::FromInt(MakeDay(year, month, date));
6840}
6841
6842
6843static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6844static const int kDaysIn4Years = 4 * 365 + 1;
6845static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6846static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6847static const int kDays1970to2000 = 30 * 365 + 7;
6848static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6849 kDays1970to2000;
6850static const int kYearsOffset = 400000;
6851
6852static const char kDayInYear[] = {
6853 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6854 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6855 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6856 22, 23, 24, 25, 26, 27, 28,
6857 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6858 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6859 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6860 22, 23, 24, 25, 26, 27, 28, 29, 30,
6861 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6862 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6863 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6864 22, 23, 24, 25, 26, 27, 28, 29, 30,
6865 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6866 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6867 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6868 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6869 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6870 22, 23, 24, 25, 26, 27, 28, 29, 30,
6871 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6872 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6873 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6874 22, 23, 24, 25, 26, 27, 28, 29, 30,
6875 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6876 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6877
6878 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6879 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6880 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6881 22, 23, 24, 25, 26, 27, 28,
6882 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6883 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6884 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6885 22, 23, 24, 25, 26, 27, 28, 29, 30,
6886 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6887 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6888 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6889 22, 23, 24, 25, 26, 27, 28, 29, 30,
6890 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6891 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6892 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6893 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6894 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6895 22, 23, 24, 25, 26, 27, 28, 29, 30,
6896 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6897 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6898 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6899 22, 23, 24, 25, 26, 27, 28, 29, 30,
6900 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6901 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6902
6903 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6904 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6905 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6906 22, 23, 24, 25, 26, 27, 28, 29,
6907 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6908 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6909 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6910 22, 23, 24, 25, 26, 27, 28, 29, 30,
6911 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6912 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6913 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6914 22, 23, 24, 25, 26, 27, 28, 29, 30,
6915 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6916 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6917 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6918 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6919 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6920 22, 23, 24, 25, 26, 27, 28, 29, 30,
6921 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6922 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6923 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6924 22, 23, 24, 25, 26, 27, 28, 29, 30,
6925 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6926 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6927
6928 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6929 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6930 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6931 22, 23, 24, 25, 26, 27, 28,
6932 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6933 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6934 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6935 22, 23, 24, 25, 26, 27, 28, 29, 30,
6936 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6937 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6939 22, 23, 24, 25, 26, 27, 28, 29, 30,
6940 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6941 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6942 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6943 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6944 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6945 22, 23, 24, 25, 26, 27, 28, 29, 30,
6946 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6947 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6948 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6949 22, 23, 24, 25, 26, 27, 28, 29, 30,
6950 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6951 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6952
6953static const char kMonthInYear[] = {
6954 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6955 0, 0, 0, 0, 0, 0,
6956 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6957 1, 1, 1,
6958 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6959 2, 2, 2, 2, 2, 2,
6960 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6961 3, 3, 3, 3, 3,
6962 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6963 4, 4, 4, 4, 4, 4,
6964 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6965 5, 5, 5, 5, 5,
6966 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6967 6, 6, 6, 6, 6, 6,
6968 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6969 7, 7, 7, 7, 7, 7,
6970 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6971 8, 8, 8, 8, 8,
6972 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6973 9, 9, 9, 9, 9, 9,
6974 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6975 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6976 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6977 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6978
6979 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6980 0, 0, 0, 0, 0, 0,
6981 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6982 1, 1, 1,
6983 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6984 2, 2, 2, 2, 2, 2,
6985 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6986 3, 3, 3, 3, 3,
6987 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6988 4, 4, 4, 4, 4, 4,
6989 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6990 5, 5, 5, 5, 5,
6991 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6992 6, 6, 6, 6, 6, 6,
6993 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6994 7, 7, 7, 7, 7, 7,
6995 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6996 8, 8, 8, 8, 8,
6997 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6998 9, 9, 9, 9, 9, 9,
6999 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7000 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7001 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7002 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7003
7004 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7005 0, 0, 0, 0, 0, 0,
7006 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7007 1, 1, 1, 1,
7008 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7009 2, 2, 2, 2, 2, 2,
7010 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7011 3, 3, 3, 3, 3,
7012 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7013 4, 4, 4, 4, 4, 4,
7014 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7015 5, 5, 5, 5, 5,
7016 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7017 6, 6, 6, 6, 6, 6,
7018 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7019 7, 7, 7, 7, 7, 7,
7020 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7021 8, 8, 8, 8, 8,
7022 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7023 9, 9, 9, 9, 9, 9,
7024 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7025 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7026 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7027 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7028
7029 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7030 0, 0, 0, 0, 0, 0,
7031 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7032 1, 1, 1,
7033 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7034 2, 2, 2, 2, 2, 2,
7035 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7036 3, 3, 3, 3, 3,
7037 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7038 4, 4, 4, 4, 4, 4,
7039 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7040 5, 5, 5, 5, 5,
7041 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7042 6, 6, 6, 6, 6, 6,
7043 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7044 7, 7, 7, 7, 7, 7,
7045 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7046 8, 8, 8, 8, 8,
7047 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7048 9, 9, 9, 9, 9, 9,
7049 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7050 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7051 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7052 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7053
7054
7055// This function works for dates from 1970 to 2099.
7056static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007057 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007058#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007059 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007060#endif
7061
7062 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7063 date %= kDaysIn4Years;
7064
7065 month = kMonthInYear[date];
7066 day = kDayInYear[date];
7067
7068 ASSERT(MakeDay(year, month, day) == save_date);
7069}
7070
7071
7072static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007073 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007074#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007075 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007076#endif
7077
7078 date += kDaysOffset;
7079 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7080 date %= kDaysIn400Years;
7081
7082 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7083
7084 date--;
7085 int yd1 = date / kDaysIn100Years;
7086 date %= kDaysIn100Years;
7087 year += 100 * yd1;
7088
7089 date++;
7090 int yd2 = date / kDaysIn4Years;
7091 date %= kDaysIn4Years;
7092 year += 4 * yd2;
7093
7094 date--;
7095 int yd3 = date / 365;
7096 date %= 365;
7097 year += yd3;
7098
7099 bool is_leap = (!yd1 || yd2) && !yd3;
7100
7101 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007102 ASSERT(is_leap || (date >= 0));
7103 ASSERT((date < 365) || (is_leap && (date < 366)));
7104 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7105 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7106 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007107
7108 if (is_leap) {
7109 day = kDayInYear[2*365 + 1 + date];
7110 month = kMonthInYear[2*365 + 1 + date];
7111 } else {
7112 day = kDayInYear[date];
7113 month = kMonthInYear[date];
7114 }
7115
7116 ASSERT(MakeDay(year, month, day) == save_date);
7117}
7118
7119
7120static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007121 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007122 if (date >= 0 && date < 32 * kDaysIn4Years) {
7123 DateYMDFromTimeAfter1970(date, year, month, day);
7124 } else {
7125 DateYMDFromTimeSlow(date, year, month, day);
7126 }
7127}
7128
7129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007130RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007131 NoHandleAllocation ha;
7132 ASSERT(args.length() == 2);
7133
7134 CONVERT_DOUBLE_CHECKED(t, args[0]);
7135 CONVERT_CHECKED(JSArray, res_array, args[1]);
7136
7137 int year, month, day;
7138 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007140 RUNTIME_ASSERT(res_array->elements()->map() ==
7141 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007142 FixedArray* elms = FixedArray::cast(res_array->elements());
7143 RUNTIME_ASSERT(elms->length() == 3);
7144
7145 elms->set(0, Smi::FromInt(year));
7146 elms->set(1, Smi::FromInt(month));
7147 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007149 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007150}
7151
7152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007153RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007154 NoHandleAllocation ha;
7155 ASSERT(args.length() == 3);
7156
7157 JSFunction* callee = JSFunction::cast(args[0]);
7158 Object** parameters = reinterpret_cast<Object**>(args[1]);
7159 const int length = Smi::cast(args[2])->value();
7160
lrn@chromium.org303ada72010-10-27 09:33:13 +00007161 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007162 { MaybeObject* maybe_result =
7163 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007164 if (!maybe_result->ToObject(&result)) return maybe_result;
7165 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007166 // Allocate the elements if needed.
7167 if (length > 0) {
7168 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007169 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007171 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7172 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007173
7174 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007175 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007177 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007178
7179 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007180 for (int i = 0; i < length; i++) {
7181 array->set(i, *--parameters, mode);
7182 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007183 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007184 }
7185 return result;
7186}
7187
7188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007189RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007191 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007192 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007193 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007194 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007195
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007196 // Allocate global closures in old space and allocate local closures
7197 // in new space. Additionally pretenure closures that are assigned
7198 // directly to properties.
7199 pretenure = pretenure || (context->global_context() == *context);
7200 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007201 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007202 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7203 context,
7204 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007205 return *result;
7206}
7207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007208
7209static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7210 int* total_argc) {
7211 // Find frame containing arguments passed to the caller.
7212 JavaScriptFrameIterator it;
7213 JavaScriptFrame* frame = it.frame();
7214 List<JSFunction*> functions(2);
7215 frame->GetFunctions(&functions);
7216 if (functions.length() > 1) {
7217 int inlined_frame_index = functions.length() - 1;
7218 JSFunction* inlined_function = functions[inlined_frame_index];
7219 int args_count = inlined_function->shared()->formal_parameter_count();
7220 ScopedVector<SlotRef> args_slots(args_count);
7221 SlotRef::ComputeSlotMappingForArguments(frame,
7222 inlined_frame_index,
7223 &args_slots);
7224
7225 *total_argc = bound_argc + args_count;
7226 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7227 for (int i = 0; i < args_count; i++) {
7228 Handle<Object> val = args_slots[i].GetValue();
7229 param_data[bound_argc + i] = val.location();
7230 }
7231 return param_data;
7232 } else {
7233 it.AdvanceToArgumentsFrame();
7234 frame = it.frame();
7235 int args_count = frame->ComputeParametersCount();
7236
7237 *total_argc = bound_argc + args_count;
7238 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7239 for (int i = 0; i < args_count; i++) {
7240 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7241 param_data[bound_argc + i] = val.location();
7242 }
7243 return param_data;
7244 }
7245}
7246
7247
7248RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007249 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007250 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007251 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007252 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007253
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007254 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007255 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007256 int bound_argc = 0;
7257 if (!args[1]->IsNull()) {
7258 CONVERT_ARG_CHECKED(JSArray, params, 1);
7259 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007260 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007261 bound_argc = Smi::cast(params->length())->value();
7262 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007264 int total_argc = 0;
7265 SmartPointer<Object**> param_data =
7266 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007267 for (int i = 0; i < bound_argc; i++) {
7268 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007269 param_data[i] = val.location();
7270 }
7271
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007272 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007273 Handle<Object> result =
7274 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007275 if (exception) {
7276 return Failure::Exception();
7277 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007278
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007279 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007280 return *result;
7281}
7282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007284static void TrySettingInlineConstructStub(Isolate* isolate,
7285 Handle<JSFunction> function) {
7286 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007287 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007289 }
7290 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007291 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007292 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007293 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007294 function->shared()->set_construct_stub(
7295 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007296 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007297 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007298}
7299
7300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007301RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303 ASSERT(args.length() == 1);
7304
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007305 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007307 // If the constructor isn't a proper function we throw a type error.
7308 if (!constructor->IsJSFunction()) {
7309 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7310 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007311 isolate->factory()->NewTypeError("not_constructor", arguments);
7312 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007313 }
7314
7315 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007316
7317 // If function should not have prototype, construction is not allowed. In this
7318 // case generated code bailouts here, since function has no initial_map.
7319 if (!function->should_have_prototype()) {
7320 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7321 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 isolate->factory()->NewTypeError("not_constructor", arguments);
7323 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007324 }
7325
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007326#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007328 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 if (debug->StepInActive()) {
7330 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007331 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007332#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007334 if (function->has_initial_map()) {
7335 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336 // The 'Function' function ignores the receiver object when
7337 // called using 'new' and creates a new JSFunction object that
7338 // is returned. The receiver object is only used for error
7339 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007341 // allocate JSFunctions since it does not properly initialize
7342 // the shared part of the function. Since the receiver is
7343 // ignored anyway, we use the global object as the receiver
7344 // instead of a new JSFunction object. This way, errors are
7345 // reported the same way whether or not 'Function' is called
7346 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349 }
7350
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007351 // The function should be compiled for the optimization hints to be
7352 // available. We cannot use EnsureCompiled because that forces a
7353 // compilation through the shared function info which makes it
7354 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007356 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007357
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007358 if (!function->has_initial_map() &&
7359 shared->IsInobjectSlackTrackingInProgress()) {
7360 // The tracking is already in progress for another function. We can only
7361 // track one initial_map at a time, so we force the completion before the
7362 // function is called as a constructor for the first time.
7363 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007364 }
7365
7366 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007367 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7368 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007369 // Delay setting the stub if inobject slack tracking is in progress.
7370 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007372 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 isolate->counters()->constructed_objects()->Increment();
7375 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007376
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007377 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378}
7379
7380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007381RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007383 ASSERT(args.length() == 1);
7384
7385 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7386 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007390}
7391
7392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395 ASSERT(args.length() == 1);
7396
7397 Handle<JSFunction> function = args.at<JSFunction>(0);
7398#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007399 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007401 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 PrintF("]\n");
7403 }
7404#endif
7405
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007406 // Compile the target function. Here we compile using CompileLazyInLoop in
7407 // order to get the optimized version. This helps code like delta-blue
7408 // that calls performance-critical routines through constructors. A
7409 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7410 // direct call. Since the in-loop tracking takes place through CallICs
7411 // this means that things called through constructors are never known to
7412 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007414 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415 return Failure::Exception();
7416 }
7417
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007418 // All done. Return the compiled code.
7419 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 return function->code();
7421}
7422
7423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007426 ASSERT(args.length() == 1);
7427 Handle<JSFunction> function = args.at<JSFunction>(0);
7428 // If the function is not optimizable or debugger is active continue using the
7429 // code from the full compiler.
7430 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007431 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007432 if (FLAG_trace_opt) {
7433 PrintF("[failed to optimize ");
7434 function->PrintName();
7435 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7436 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007437 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007438 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007439 function->ReplaceCode(function->shared()->code());
7440 return function->code();
7441 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007442 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007443 return function->code();
7444 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007445 if (FLAG_trace_opt) {
7446 PrintF("[failed to optimize ");
7447 function->PrintName();
7448 PrintF(": optimized compilation failed]\n");
7449 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007450 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007451 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007452}
7453
7454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007455RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007457 ASSERT(args.length() == 1);
7458 RUNTIME_ASSERT(args[0]->IsSmi());
7459 Deoptimizer::BailoutType type =
7460 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007461 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7462 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007463 int frames = deoptimizer->output_count();
7464
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007465 deoptimizer->MaterializeHeapNumbers();
7466 delete deoptimizer;
7467
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007468 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007469 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007470 for (int i = 0; i < frames - 1; i++) it.Advance();
7471 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007472
7473 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007474 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007475 Handle<Object> arguments;
7476 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007477 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007478 if (arguments.is_null()) {
7479 // FunctionGetArguments can't throw an exception, so cast away the
7480 // doubt with an assert.
7481 arguments = Handle<Object>(
7482 Accessors::FunctionGetArguments(*function,
7483 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007484 ASSERT(*arguments != isolate->heap()->null_value());
7485 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 }
7487 frame->SetExpression(i, *arguments);
7488 }
7489 }
7490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007492 if (type == Deoptimizer::EAGER) {
7493 RUNTIME_ASSERT(function->IsOptimized());
7494 } else {
7495 RUNTIME_ASSERT(!function->IsOptimized());
7496 }
7497
7498 // Avoid doing too much work when running with --always-opt and keep
7499 // the optimized code around.
7500 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007501 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007502 }
7503
7504 // Count the number of optimized activations of the function.
7505 int activations = 0;
7506 while (!it.done()) {
7507 JavaScriptFrame* frame = it.frame();
7508 if (frame->is_optimized() && frame->function() == *function) {
7509 activations++;
7510 }
7511 it.Advance();
7512 }
7513
7514 // TODO(kasperl): For now, we cannot support removing the optimized
7515 // code when we have recursive invocations of the same function.
7516 if (activations == 0) {
7517 if (FLAG_trace_deopt) {
7518 PrintF("[removing optimized code for: ");
7519 function->PrintName();
7520 PrintF("]\n");
7521 }
7522 function->ReplaceCode(function->shared()->code());
7523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007525}
7526
7527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007528RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007530 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007532}
7533
7534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007535RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007536 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007537 ASSERT(args.length() == 1);
7538 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007539 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007540
7541 Deoptimizer::DeoptimizeFunction(*function);
7542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007544}
7545
7546
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007547RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7548 HandleScope scope(isolate);
7549 ASSERT(args.length() == 1);
7550 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7551 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7552 function->MarkForLazyRecompilation();
7553 return isolate->heap()->undefined_value();
7554}
7555
7556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007557RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007558 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007559 ASSERT(args.length() == 1);
7560 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7561
7562 // We're not prepared to handle a function with arguments object.
7563 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7564
7565 // We have hit a back edge in an unoptimized frame for a function that was
7566 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007568 // Keep track of whether we've succeeded in optimizing.
7569 bool succeeded = unoptimized->optimizable();
7570 if (succeeded) {
7571 // If we are trying to do OSR when there are already optimized
7572 // activations of the function, it means (a) the function is directly or
7573 // indirectly recursive and (b) an optimized invocation has been
7574 // deoptimized so that we are currently in an unoptimized activation.
7575 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007576 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007577 while (succeeded && !it.done()) {
7578 JavaScriptFrame* frame = it.frame();
7579 succeeded = !frame->is_optimized() || frame->function() != *function;
7580 it.Advance();
7581 }
7582 }
7583
7584 int ast_id = AstNode::kNoNumber;
7585 if (succeeded) {
7586 // The top JS function is this one, the PC is somewhere in the
7587 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007588 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007589 JavaScriptFrame* frame = it.frame();
7590 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007591 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007592 ASSERT(unoptimized->contains(frame->pc()));
7593
7594 // Use linear search of the unoptimized code's stack check table to find
7595 // the AST id matching the PC.
7596 Address start = unoptimized->instruction_start();
7597 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007598 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007599 uint32_t table_length = Memory::uint32_at(table_cursor);
7600 table_cursor += kIntSize;
7601 for (unsigned i = 0; i < table_length; ++i) {
7602 // Table entries are (AST id, pc offset) pairs.
7603 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7604 if (pc_offset == target_pc_offset) {
7605 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7606 break;
7607 }
7608 table_cursor += 2 * kIntSize;
7609 }
7610 ASSERT(ast_id != AstNode::kNoNumber);
7611 if (FLAG_trace_osr) {
7612 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7613 function->PrintName();
7614 PrintF("]\n");
7615 }
7616
7617 // Try to compile the optimized code. A true return value from
7618 // CompileOptimized means that compilation succeeded, not necessarily
7619 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007620 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7621 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007622 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7623 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007624 if (data->OsrPcOffset()->value() >= 0) {
7625 if (FLAG_trace_osr) {
7626 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007627 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007628 }
7629 ASSERT(data->OsrAstId()->value() == ast_id);
7630 } else {
7631 // We may never generate the desired OSR entry if we emit an
7632 // early deoptimize.
7633 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007634 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007635 } else {
7636 succeeded = false;
7637 }
7638 }
7639
7640 // Revert to the original stack checks in the original unoptimized code.
7641 if (FLAG_trace_osr) {
7642 PrintF("[restoring original stack checks in ");
7643 function->PrintName();
7644 PrintF("]\n");
7645 }
7646 StackCheckStub check_stub;
7647 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007648 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007649 Deoptimizer::RevertStackCheckCode(*unoptimized,
7650 *check_code,
7651 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007652
7653 // Allow OSR only at nesting level zero again.
7654 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7655
7656 // If the optimization attempt succeeded, return the AST id tagged as a
7657 // smi. This tells the builtin that we need to translate the unoptimized
7658 // frame to an optimized one.
7659 if (succeeded) {
7660 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7661 return Smi::FromInt(ast_id);
7662 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007663 if (function->IsMarkedForLazyRecompilation()) {
7664 function->ReplaceCode(function->shared()->code());
7665 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007666 return Smi::FromInt(-1);
7667 }
7668}
7669
7670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007671RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007672 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007673 ASSERT(args.length() == 1);
7674 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7675 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7676}
7677
7678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007680 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007681 ASSERT(args.length() == 1);
7682 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7683 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7684}
7685
7686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007687RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007688 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007689 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007690
kasper.lund7276f142008-07-30 08:49:36 +00007691 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007692 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007693 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 { MaybeObject* maybe_result =
7695 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007696 if (!maybe_result->ToObject(&result)) return maybe_result;
7697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007699 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007700
kasper.lund7276f142008-07-30 08:49:36 +00007701 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007702}
7703
lrn@chromium.org303ada72010-10-27 09:33:13 +00007704
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7706 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007707 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007708 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007709 Object* js_object = object;
7710 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007711 MaybeObject* maybe_js_object = js_object->ToObject();
7712 if (!maybe_js_object->ToObject(&js_object)) {
7713 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7714 return maybe_js_object;
7715 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007716 HandleScope scope(isolate);
7717 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007719 isolate->factory()->NewTypeError("with_expression",
7720 HandleVector(&handle, 1));
7721 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007722 }
7723 }
7724
lrn@chromium.org303ada72010-10-27 09:33:13 +00007725 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007726 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7727 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007728 if (!maybe_result->ToObject(&result)) return maybe_result;
7729 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007731 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007733
kasper.lund7276f142008-07-30 08:49:36 +00007734 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735}
7736
7737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007738RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007739 NoHandleAllocation ha;
7740 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007742}
7743
7744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007745RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007746 NoHandleAllocation ha;
7747 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007748 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007749}
7750
7751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007752RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007754 ASSERT(args.length() == 2);
7755
7756 CONVERT_ARG_CHECKED(Context, context, 0);
7757 CONVERT_ARG_CHECKED(String, name, 1);
7758
7759 int index;
7760 PropertyAttributes attributes;
7761 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007762 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007763
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007764 // If the slot was not found the result is true.
7765 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007766 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007767 }
7768
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007769 // If the slot was found in a context, it should be DONT_DELETE.
7770 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007771 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007772 }
7773
7774 // The slot was found in a JSObject, either a context extension object,
7775 // the global object, or an arguments object. Try to delete it
7776 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7777 // which allows deleting all parameters in functions that mention
7778 // 'arguments', we do this even for the case of slots found on an
7779 // arguments object. The slot was found on an arguments object if the
7780 // index is non-negative.
7781 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7782 if (index >= 0) {
7783 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7784 } else {
7785 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7786 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007787}
7788
7789
ager@chromium.orga1645e22009-09-09 19:27:10 +00007790// A mechanism to return a pair of Object pointers in registers (if possible).
7791// How this is achieved is calling convention-dependent.
7792// All currently supported x86 compiles uses calling conventions that are cdecl
7793// variants where a 64-bit value is returned in two 32-bit registers
7794// (edx:eax on ia32, r1:r0 on ARM).
7795// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7796// In Win64 calling convention, a struct of two pointers is returned in memory,
7797// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007798#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007799struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007800 MaybeObject* x;
7801 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007802};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007803
lrn@chromium.org303ada72010-10-27 09:33:13 +00007804static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007805 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007806 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7807 // In Win64 they are assigned to a hidden first argument.
7808 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007809}
7810#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007811typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007812static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007813 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007814 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007815}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007816#endif
7817
7818
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007819static inline MaybeObject* Unhole(Heap* heap,
7820 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007821 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007822 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7823 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825}
7826
7827
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007828static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7829 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007830 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007831 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007832 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007833 JSFunction* context_extension_function =
7834 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007835 // If the holder isn't a context extension object, we just return it
7836 // as the receiver. This allows arguments objects to be used as
7837 // receivers, but only if they are put in the context scope chain
7838 // explicitly via a with-statement.
7839 Object* constructor = holder->map()->constructor();
7840 if (constructor != context_extension_function) return holder;
7841 // Fall back to using the global object as the receiver if the
7842 // property turns out to be a local variable allocated in a context
7843 // extension object - introduced via eval.
7844 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007845}
7846
7847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007848static ObjectPair LoadContextSlotHelper(Arguments args,
7849 Isolate* isolate,
7850 bool throw_error) {
7851 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007852 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007853
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007854 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007855 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007858 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007859
7860 int index;
7861 PropertyAttributes attributes;
7862 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007863 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007864
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007865 // If the index is non-negative, the slot has been found in a local
7866 // variable or a parameter. Read it from the context object or the
7867 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007868 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007869 // If the "property" we were looking for is a local variable or an
7870 // argument in a context, the receiver is the global object; see
7871 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007872 JSObject* receiver =
7873 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007874 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007875 ? Context::cast(*holder)->get(index)
7876 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007877 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007878 }
7879
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007880 // If the holder is found, we read the property from it.
7881 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007882 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007883 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007884 JSObject* receiver;
7885 if (object->IsGlobalObject()) {
7886 receiver = GlobalObject::cast(object)->global_receiver();
7887 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007889 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007890 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007891 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007892 // No need to unhole the value here. This is taken care of by the
7893 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007894 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007895 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007896 }
7897
7898 if (throw_error) {
7899 // The property doesn't exist - throw exception.
7900 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007901 isolate->factory()->NewReferenceError("not_defined",
7902 HandleVector(&name, 1));
7903 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007904 } else {
7905 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007906 return MakePair(isolate->heap()->undefined_value(),
7907 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908 }
7909}
7910
7911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007912RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007914}
7915
7916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007917RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007918 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919}
7920
7921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007922RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007923 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007924 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007926 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007928 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007929 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7930 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7931 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007932 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007933
7934 int index;
7935 PropertyAttributes attributes;
7936 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007937 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007938
7939 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007940 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941 // Ignore if read_only variable.
7942 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007943 // Context is a fixed array and set cannot fail.
7944 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007945 } else if (strict_mode == kStrictMode) {
7946 // Setting read only property in strict mode.
7947 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 isolate->factory()->NewTypeError("strict_cannot_assign",
7949 HandleVector(&name, 1));
7950 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007951 }
7952 } else {
7953 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007954 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007955 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007956 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007957 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007958 return Failure::Exception();
7959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007960 }
7961 return *value;
7962 }
7963
7964 // Slow case: The property is not in a FixedArray context.
7965 // It is either in an JSObject extension context or it was not found.
7966 Handle<JSObject> context_ext;
7967
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007968 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007969 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007970 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007971 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007972 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007973 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007974
7975 if (strict_mode == kStrictMode) {
7976 // Throw in strict mode (assignment to undefined variable).
7977 Handle<Object> error =
7978 isolate->factory()->NewReferenceError(
7979 "not_defined", HandleVector(&name, 1));
7980 return isolate->Throw(*error);
7981 }
7982 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007984 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007985 }
7986
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007987 // Set the property, but ignore if read_only variable on the context
7988 // extension object itself.
7989 if ((attributes & READ_ONLY) == 0 ||
7990 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007991 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007992 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007993 SetProperty(context_ext, name, value, NONE, strict_mode));
7994 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007995 // Setting read only property in strict mode.
7996 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 isolate->factory()->NewTypeError(
7998 "strict_cannot_assign", HandleVector(&name, 1));
7999 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008000 }
8001 return *value;
8002}
8003
8004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008005RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008006 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008007 ASSERT(args.length() == 1);
8008
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008009 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008010}
8011
8012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008013RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 ASSERT(args.length() == 1);
8016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018}
8019
8020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008021RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008022 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008023 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008024}
8025
8026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008027RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008028 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029 ASSERT(args.length() == 1);
8030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008031 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008033 isolate->factory()->NewReferenceError("not_defined",
8034 HandleVector(&name, 1));
8035 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036}
8037
8038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008039RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008040 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041
8042 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043 if (isolate->stack_guard()->IsStackOverflow()) {
8044 NoHandleAllocation na;
8045 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008048 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049}
8050
8051
8052// NOTE: These PrintXXX functions are defined for all builds (not just
8053// DEBUG builds) because we may want to be able to trace function
8054// calls in all modes.
8055static void PrintString(String* str) {
8056 // not uncommon to have empty strings
8057 if (str->length() > 0) {
8058 SmartPointer<char> s =
8059 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8060 PrintF("%s", *s);
8061 }
8062}
8063
8064
8065static void PrintObject(Object* obj) {
8066 if (obj->IsSmi()) {
8067 PrintF("%d", Smi::cast(obj)->value());
8068 } else if (obj->IsString() || obj->IsSymbol()) {
8069 PrintString(String::cast(obj));
8070 } else if (obj->IsNumber()) {
8071 PrintF("%g", obj->Number());
8072 } else if (obj->IsFailure()) {
8073 PrintF("<failure>");
8074 } else if (obj->IsUndefined()) {
8075 PrintF("<undefined>");
8076 } else if (obj->IsNull()) {
8077 PrintF("<null>");
8078 } else if (obj->IsTrue()) {
8079 PrintF("<true>");
8080 } else if (obj->IsFalse()) {
8081 PrintF("<false>");
8082 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008083 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008084 }
8085}
8086
8087
8088static int StackSize() {
8089 int n = 0;
8090 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8091 return n;
8092}
8093
8094
8095static void PrintTransition(Object* result) {
8096 // indentation
8097 { const int nmax = 80;
8098 int n = StackSize();
8099 if (n <= nmax)
8100 PrintF("%4d:%*s", n, n, "");
8101 else
8102 PrintF("%4d:%*s", n, nmax, "...");
8103 }
8104
8105 if (result == NULL) {
8106 // constructor calls
8107 JavaScriptFrameIterator it;
8108 JavaScriptFrame* frame = it.frame();
8109 if (frame->IsConstructor()) PrintF("new ");
8110 // function name
8111 Object* fun = frame->function();
8112 if (fun->IsJSFunction()) {
8113 PrintObject(JSFunction::cast(fun)->shared()->name());
8114 } else {
8115 PrintObject(fun);
8116 }
8117 // function arguments
8118 // (we are intentionally only printing the actually
8119 // supplied parameters, not all parameters required)
8120 PrintF("(this=");
8121 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008122 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008123 for (int i = 0; i < length; i++) {
8124 PrintF(", ");
8125 PrintObject(frame->GetParameter(i));
8126 }
8127 PrintF(") {\n");
8128
8129 } else {
8130 // function result
8131 PrintF("} -> ");
8132 PrintObject(result);
8133 PrintF("\n");
8134 }
8135}
8136
8137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008138RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008139 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008140 NoHandleAllocation ha;
8141 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008142 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008143}
8144
8145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008146RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008147 NoHandleAllocation ha;
8148 PrintTransition(args[0]);
8149 return args[0]; // return TOS
8150}
8151
8152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008153RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008154 NoHandleAllocation ha;
8155 ASSERT(args.length() == 1);
8156
8157#ifdef DEBUG
8158 if (args[0]->IsString()) {
8159 // If we have a string, assume it's a code "marker"
8160 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008161 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008162 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008163 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8164 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008165 } else {
8166 PrintF("DebugPrint: ");
8167 }
8168 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008169 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008170 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008171 HeapObject::cast(args[0])->map()->Print();
8172 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008174 // ShortPrint is available in release mode. Print is not.
8175 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008176#endif
8177 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008178 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008179
8180 return args[0]; // return TOS
8181}
8182
8183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008184RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008185 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008187 isolate->PrintStack();
8188 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008189}
8190
8191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008192RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008194 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008195
8196 // According to ECMA-262, section 15.9.1, page 117, the precision of
8197 // the number in a Date object representing a particular instant in
8198 // time is milliseconds. Therefore, we floor the result of getting
8199 // the OS time.
8200 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008202}
8203
8204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008205RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008207 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008209 CONVERT_ARG_CHECKED(String, str, 0);
8210 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008212 CONVERT_ARG_CHECKED(JSArray, output, 1);
8213 RUNTIME_ASSERT(output->HasFastElements());
8214
8215 AssertNoAllocation no_allocation;
8216
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008217 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008218 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8219 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008220 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008221 result = DateParser::Parse(str->ToAsciiVector(),
8222 output_array,
8223 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008225 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008226 result = DateParser::Parse(str->ToUC16Vector(),
8227 output_array,
8228 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008229 }
8230
8231 if (result) {
8232 return *output;
8233 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008234 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008235 }
8236}
8237
8238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008239RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240 NoHandleAllocation ha;
8241 ASSERT(args.length() == 1);
8242
8243 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008244 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008245 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246}
8247
8248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008249RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008251 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008252
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008253 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008254}
8255
8256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008257RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 NoHandleAllocation ha;
8259 ASSERT(args.length() == 1);
8260
8261 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263}
8264
8265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008266RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008267 ASSERT(args.length() == 1);
8268 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008269 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008270 return JSGlobalObject::cast(global)->global_receiver();
8271}
8272
8273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008274RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008275 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008276 ASSERT_EQ(1, args.length());
8277 CONVERT_ARG_CHECKED(String, source, 0);
8278
8279 Handle<Object> result = JsonParser::Parse(source);
8280 if (result.is_null()) {
8281 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008283 return Failure::Exception();
8284 }
8285 return *result;
8286}
8287
8288
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008289bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8290 Handle<Context> context) {
8291 if (context->allow_code_gen_from_strings()->IsFalse()) {
8292 // Check with callback if set.
8293 AllowCodeGenerationFromStringsCallback callback =
8294 isolate->allow_code_gen_callback();
8295 if (callback == NULL) {
8296 // No callback set and code generation disallowed.
8297 return false;
8298 } else {
8299 // Callback set. Let it decide if code generation is allowed.
8300 VMState state(isolate, EXTERNAL);
8301 return callback(v8::Utils::ToLocal(context));
8302 }
8303 }
8304 return true;
8305}
8306
8307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008308RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008310 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008311 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008312
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008313 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008314 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008315
8316 // Check if global context allows code generation from
8317 // strings. Throw an exception if it doesn't.
8318 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8319 return isolate->Throw(*isolate->factory()->NewError(
8320 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8321 }
8322
8323 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008324 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8325 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008326 true,
8327 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008328 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008329 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008330 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8331 context,
8332 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 return *fun;
8334}
8335
8336
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337static ObjectPair CompileGlobalEval(Isolate* isolate,
8338 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008339 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008340 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008341 Handle<Context> context = Handle<Context>(isolate->context());
8342 Handle<Context> global_context = Handle<Context>(context->global_context());
8343
8344 // Check if global context allows code generation from
8345 // strings. Throw an exception if it doesn't.
8346 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8347 isolate->Throw(*isolate->factory()->NewError(
8348 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8349 return MakePair(Failure::Exception(), NULL);
8350 }
8351
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008352 // Deal with a normal eval call with a string argument. Compile it
8353 // and return the compiled function bound in the local context.
8354 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8355 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008356 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008357 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008358 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008359 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008360 Handle<JSFunction> compiled =
8361 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008362 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008363 return MakePair(*compiled, *receiver);
8364}
8365
8366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008367RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008368 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008370 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008371 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008372 Handle<Object> receiver; // Will be overwritten.
8373
8374 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008375 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008376#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008377 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008378 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008379 StackFrameLocator locator;
8380 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008381 ASSERT(Context::cast(frame->context()) == *context);
8382#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008383
8384 // Find where the 'eval' symbol is bound. It is unaliased only if
8385 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008386 int index = -1;
8387 PropertyAttributes attributes = ABSENT;
8388 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008389 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8390 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008391 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008392 // Stop search when eval is found or when the global context is
8393 // reached.
8394 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008395 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008396 context = Handle<Context>(Context::cast(context->closure()->context()),
8397 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008398 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008399 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008400 }
8401 }
8402
iposva@chromium.org245aa852009-02-10 00:49:54 +00008403 // If eval could not be resolved, it has been deleted and we need to
8404 // throw a reference error.
8405 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008406 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008407 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008408 isolate->factory()->NewReferenceError("not_defined",
8409 HandleVector(&name, 1));
8410 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008411 }
8412
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008413 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008414 // 'eval' is not bound in the global context. Just call the function
8415 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008416 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 receiver = Handle<JSObject>(
8418 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008419 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008420 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008421 }
8422
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008423 // 'eval' is bound in the global context, but it may have been overwritten.
8424 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008425 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008426 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008427 return MakePair(*callee,
8428 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008429 }
8430
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008431 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 return CompileGlobalEval(isolate,
8433 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008434 args.at<Object>(2),
8435 static_cast<StrictModeFlag>(
8436 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008437}
8438
8439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008440RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008441 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008442
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008443 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008444 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008445
8446 // 'eval' is bound in the global context, but it may have been overwritten.
8447 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008449 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 return MakePair(*callee,
8451 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008452 }
8453
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008454 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008455 return CompileGlobalEval(isolate,
8456 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008457 args.at<Object>(2),
8458 static_cast<StrictModeFlag>(
8459 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008460}
8461
8462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008463RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008464 // This utility adjusts the property attributes for newly created Function
8465 // object ("new Function(...)") by changing the map.
8466 // All it does is changing the prototype property to enumerable
8467 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008468 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008469 ASSERT(args.length() == 1);
8470 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471
8472 Handle<Map> map = func->shared()->strict_mode()
8473 ? isolate->strict_mode_function_instance_map()
8474 : isolate->function_instance_map();
8475
8476 ASSERT(func->map()->instance_type() == map->instance_type());
8477 ASSERT(func->map()->instance_size() == map->instance_size());
8478 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008479 return *func;
8480}
8481
8482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008483RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008484 // Allocate a block of memory in NewSpace (filled with a filler).
8485 // Use as fallback for allocation in generated code when NewSpace
8486 // is full.
8487 ASSERT(args.length() == 1);
8488 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8489 int size = size_smi->value();
8490 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8491 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 Heap* heap = isolate->heap();
8493 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008494 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008495 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008497 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008498 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008499 }
8500 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008501 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008502}
8503
8504
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008505// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008506// array. Returns true if the element was pushed on the stack and
8507// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008508RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008509 ASSERT(args.length() == 2);
8510 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008511 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008512 RUNTIME_ASSERT(array->HasFastElements());
8513 int length = Smi::cast(array->length())->value();
8514 FixedArray* elements = FixedArray::cast(array->elements());
8515 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008516 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008517 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008518 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008519 // Strict not needed. Used for cycle detection in Array join implementation.
8520 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8521 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008522 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008524 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008525}
8526
8527
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008528/**
8529 * A simple visitor visits every element of Array's.
8530 * The backend storage can be a fixed array for fast elements case,
8531 * or a dictionary for sparse array. Since Dictionary is a subtype
8532 * of FixedArray, the class can be used by both fast and slow cases.
8533 * The second parameter of the constructor, fast_elements, specifies
8534 * whether the storage is a FixedArray or Dictionary.
8535 *
8536 * An index limit is used to deal with the situation that a result array
8537 * length overflows 32-bit non-negative integer.
8538 */
8539class ArrayConcatVisitor {
8540 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008541 ArrayConcatVisitor(Isolate* isolate,
8542 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008543 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008544 isolate_(isolate),
8545 storage_(Handle<FixedArray>::cast(
8546 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008547 index_offset_(0u),
8548 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008549
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008550 ~ArrayConcatVisitor() {
8551 clear_storage();
8552 }
8553
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008554 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008555 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008556 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008557
8558 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008559 if (index < static_cast<uint32_t>(storage_->length())) {
8560 storage_->set(index, *elm);
8561 return;
8562 }
8563 // Our initial estimate of length was foiled, possibly by
8564 // getters on the arrays increasing the length of later arrays
8565 // during iteration.
8566 // This shouldn't happen in anything but pathological cases.
8567 SetDictionaryMode(index);
8568 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008569 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008570 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008571 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008572 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008573 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008574 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008575 // Dictionary needed to grow.
8576 clear_storage();
8577 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008578 }
8579}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008580
8581 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008582 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8583 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008584 } else {
8585 index_offset_ += delta;
8586 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008587 }
8588
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008590 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008591 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008592 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008593 Handle<Map> map;
8594 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008595 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008596 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008597 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008598 }
8599 array->set_map(*map);
8600 array->set_length(*length);
8601 array->set_elements(*storage_);
8602 return array;
8603 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008604
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008605 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008606 // Convert storage to dictionary mode.
8607 void SetDictionaryMode(uint32_t index) {
8608 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008609 Handle<FixedArray> current_storage(*storage_);
8610 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008612 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8613 for (uint32_t i = 0; i < current_length; i++) {
8614 HandleScope loop_scope;
8615 Handle<Object> element(current_storage->get(i));
8616 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008617 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008618 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008619 if (!new_storage.is_identical_to(slow_storage)) {
8620 slow_storage = loop_scope.CloseAndEscape(new_storage);
8621 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008622 }
8623 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008624 clear_storage();
8625 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008626 fast_elements_ = false;
8627 }
8628
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008629 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008630 isolate_->global_handles()->Destroy(
8631 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008632 }
8633
8634 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008635 storage_ = Handle<FixedArray>::cast(
8636 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008637 }
8638
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008639 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008640 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008641 // Index after last seen index. Always less than or equal to
8642 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008643 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008644 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008645};
8646
8647
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008648static uint32_t EstimateElementCount(Handle<JSArray> array) {
8649 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8650 int element_count = 0;
8651 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008652 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008653 // Fast elements can't have lengths that are not representable by
8654 // a 32-bit signed integer.
8655 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8656 int fast_length = static_cast<int>(length);
8657 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8658 for (int i = 0; i < fast_length; i++) {
8659 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008660 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008661 break;
8662 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008663 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008664 Handle<NumberDictionary> dictionary(
8665 NumberDictionary::cast(array->elements()));
8666 int capacity = dictionary->Capacity();
8667 for (int i = 0; i < capacity; i++) {
8668 Handle<Object> key(dictionary->KeyAt(i));
8669 if (dictionary->IsKey(*key)) {
8670 element_count++;
8671 }
8672 }
8673 break;
8674 }
8675 default:
8676 // External arrays are always dense.
8677 return length;
8678 }
8679 // As an estimate, we assume that the prototype doesn't contain any
8680 // inherited elements.
8681 return element_count;
8682}
8683
8684
8685
8686template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008687static void IterateExternalArrayElements(Isolate* isolate,
8688 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008689 bool elements_are_ints,
8690 bool elements_are_guaranteed_smis,
8691 ArrayConcatVisitor* visitor) {
8692 Handle<ExternalArrayClass> array(
8693 ExternalArrayClass::cast(receiver->elements()));
8694 uint32_t len = static_cast<uint32_t>(array->length());
8695
8696 ASSERT(visitor != NULL);
8697 if (elements_are_ints) {
8698 if (elements_are_guaranteed_smis) {
8699 for (uint32_t j = 0; j < len; j++) {
8700 HandleScope loop_scope;
8701 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8702 visitor->visit(j, e);
8703 }
8704 } else {
8705 for (uint32_t j = 0; j < len; j++) {
8706 HandleScope loop_scope;
8707 int64_t val = static_cast<int64_t>(array->get(j));
8708 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8709 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8710 visitor->visit(j, e);
8711 } else {
8712 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008714 visitor->visit(j, e);
8715 }
8716 }
8717 }
8718 } else {
8719 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008720 HandleScope loop_scope(isolate);
8721 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008722 visitor->visit(j, e);
8723 }
8724 }
8725}
8726
8727
8728// Used for sorting indices in a List<uint32_t>.
8729static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8730 uint32_t a = *ap;
8731 uint32_t b = *bp;
8732 return (a == b) ? 0 : (a < b) ? -1 : 1;
8733}
8734
8735
8736static void CollectElementIndices(Handle<JSObject> object,
8737 uint32_t range,
8738 List<uint32_t>* indices) {
8739 JSObject::ElementsKind kind = object->GetElementsKind();
8740 switch (kind) {
8741 case JSObject::FAST_ELEMENTS: {
8742 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8743 uint32_t length = static_cast<uint32_t>(elements->length());
8744 if (range < length) length = range;
8745 for (uint32_t i = 0; i < length; i++) {
8746 if (!elements->get(i)->IsTheHole()) {
8747 indices->Add(i);
8748 }
8749 }
8750 break;
8751 }
8752 case JSObject::DICTIONARY_ELEMENTS: {
8753 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008754 uint32_t capacity = dict->Capacity();
8755 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008756 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008757 Handle<Object> k(dict->KeyAt(j));
8758 if (dict->IsKey(*k)) {
8759 ASSERT(k->IsNumber());
8760 uint32_t index = static_cast<uint32_t>(k->Number());
8761 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008762 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008763 }
8764 }
8765 }
8766 break;
8767 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008768 default: {
8769 int dense_elements_length;
8770 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008771 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008772 dense_elements_length =
8773 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008774 break;
8775 }
8776 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008777 dense_elements_length =
8778 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008779 break;
8780 }
8781 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008782 dense_elements_length =
8783 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008784 break;
8785 }
8786 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008787 dense_elements_length =
8788 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008789 break;
8790 }
8791 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008792 dense_elements_length =
8793 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008794 break;
8795 }
8796 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008797 dense_elements_length =
8798 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008799 break;
8800 }
8801 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008802 dense_elements_length =
8803 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008804 break;
8805 }
8806 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008807 dense_elements_length =
8808 ExternalFloatArray::cast(object->elements())->length();
8809 break;
8810 }
8811 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8812 dense_elements_length =
8813 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008814 break;
8815 }
8816 default:
8817 UNREACHABLE();
8818 dense_elements_length = 0;
8819 break;
8820 }
8821 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8822 if (range <= length) {
8823 length = range;
8824 // We will add all indices, so we might as well clear it first
8825 // and avoid duplicates.
8826 indices->Clear();
8827 }
8828 for (uint32_t i = 0; i < length; i++) {
8829 indices->Add(i);
8830 }
8831 if (length == range) return; // All indices accounted for already.
8832 break;
8833 }
8834 }
8835
8836 Handle<Object> prototype(object->GetPrototype());
8837 if (prototype->IsJSObject()) {
8838 // The prototype will usually have no inherited element indices,
8839 // but we have to check.
8840 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8841 }
8842}
8843
8844
8845/**
8846 * A helper function that visits elements of a JSArray in numerical
8847 * order.
8848 *
8849 * The visitor argument called for each existing element in the array
8850 * with the element index and the element's value.
8851 * Afterwards it increments the base-index of the visitor by the array
8852 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008853 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008854 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855static bool IterateElements(Isolate* isolate,
8856 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008857 ArrayConcatVisitor* visitor) {
8858 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8859 switch (receiver->GetElementsKind()) {
8860 case JSObject::FAST_ELEMENTS: {
8861 // Run through the elements FixedArray and use HasElement and GetElement
8862 // to check the prototype for missing elements.
8863 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8864 int fast_length = static_cast<int>(length);
8865 ASSERT(fast_length <= elements->length());
8866 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008867 HandleScope loop_scope(isolate);
8868 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008869 if (!element_value->IsTheHole()) {
8870 visitor->visit(j, element_value);
8871 } else if (receiver->HasElement(j)) {
8872 // Call GetElement on receiver, not its prototype, or getters won't
8873 // have the correct receiver.
8874 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008875 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008876 visitor->visit(j, element_value);
8877 }
8878 }
8879 break;
8880 }
8881 case JSObject::DICTIONARY_ELEMENTS: {
8882 Handle<NumberDictionary> dict(receiver->element_dictionary());
8883 List<uint32_t> indices(dict->Capacity() / 2);
8884 // Collect all indices in the object and the prototypes less
8885 // than length. This might introduce duplicates in the indices list.
8886 CollectElementIndices(receiver, length, &indices);
8887 indices.Sort(&compareUInt32);
8888 int j = 0;
8889 int n = indices.length();
8890 while (j < n) {
8891 HandleScope loop_scope;
8892 uint32_t index = indices[j];
8893 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008894 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008895 visitor->visit(index, element);
8896 // Skip to next different index (i.e., omit duplicates).
8897 do {
8898 j++;
8899 } while (j < n && indices[j] == index);
8900 }
8901 break;
8902 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008903 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8904 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8905 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008906 for (uint32_t j = 0; j < length; j++) {
8907 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8908 visitor->visit(j, e);
8909 }
8910 break;
8911 }
8912 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8913 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008914 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008915 break;
8916 }
8917 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8918 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008919 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008920 break;
8921 }
8922 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8923 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008924 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008925 break;
8926 }
8927 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8928 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008929 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008930 break;
8931 }
8932 case JSObject::EXTERNAL_INT_ELEMENTS: {
8933 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008934 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008935 break;
8936 }
8937 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8938 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008939 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008940 break;
8941 }
8942 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8943 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008944 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008945 break;
8946 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008947 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8948 IterateExternalArrayElements<ExternalDoubleArray, double>(
8949 isolate, receiver, false, false, visitor);
8950 break;
8951 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008952 default:
8953 UNREACHABLE();
8954 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008955 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008956 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008957 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008958}
8959
8960
8961/**
8962 * Array::concat implementation.
8963 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008964 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008965 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008966 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008967RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008968 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008970
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008971 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8972 int argument_count = static_cast<int>(arguments->length()->Number());
8973 RUNTIME_ASSERT(arguments->HasFastElements());
8974 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008975
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008976 // Pass 1: estimate the length and number of elements of the result.
8977 // The actual length can be larger if any of the arguments have getters
8978 // that mutate other arguments (but will otherwise be precise).
8979 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008980
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008981 uint32_t estimate_result_length = 0;
8982 uint32_t estimate_nof_elements = 0;
8983 {
8984 for (int i = 0; i < argument_count; i++) {
8985 HandleScope loop_scope;
8986 Handle<Object> obj(elements->get(i));
8987 uint32_t length_estimate;
8988 uint32_t element_estimate;
8989 if (obj->IsJSArray()) {
8990 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8991 length_estimate =
8992 static_cast<uint32_t>(array->length()->Number());
8993 element_estimate =
8994 EstimateElementCount(array);
8995 } else {
8996 length_estimate = 1;
8997 element_estimate = 1;
8998 }
8999 // Avoid overflows by capping at kMaxElementCount.
9000 if (JSObject::kMaxElementCount - estimate_result_length <
9001 length_estimate) {
9002 estimate_result_length = JSObject::kMaxElementCount;
9003 } else {
9004 estimate_result_length += length_estimate;
9005 }
9006 if (JSObject::kMaxElementCount - estimate_nof_elements <
9007 element_estimate) {
9008 estimate_nof_elements = JSObject::kMaxElementCount;
9009 } else {
9010 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009011 }
9012 }
9013 }
9014
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009015 // If estimated number of elements is more than half of length, a
9016 // fixed array (fast case) is more time and space-efficient than a
9017 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009018 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009019
9020 Handle<FixedArray> storage;
9021 if (fast_case) {
9022 // The backing storage array must have non-existing elements to
9023 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024 storage = isolate->factory()->NewFixedArrayWithHoles(
9025 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009026 } else {
9027 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9028 uint32_t at_least_space_for = estimate_nof_elements +
9029 (estimate_nof_elements >> 2);
9030 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009031 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009032 }
9033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009034 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009035
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009036 for (int i = 0; i < argument_count; i++) {
9037 Handle<Object> obj(elements->get(i));
9038 if (obj->IsJSArray()) {
9039 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009040 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009041 return Failure::Exception();
9042 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009043 } else {
9044 visitor.visit(0, obj);
9045 visitor.increase_index_offset(1);
9046 }
9047 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009048
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009049 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009050}
9051
9052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053// This will not allocate (flatten the string), but it may run
9054// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009055RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 NoHandleAllocation ha;
9057 ASSERT(args.length() == 1);
9058
9059 CONVERT_CHECKED(String, string, args[0]);
9060 StringInputBuffer buffer(string);
9061 while (buffer.has_more()) {
9062 uint16_t character = buffer.GetNext();
9063 PrintF("%c", character);
9064 }
9065 return string;
9066}
9067
ager@chromium.org5ec48922009-05-05 07:25:34 +00009068// Moves all own elements of an object, that are below a limit, to positions
9069// starting at zero. All undefined values are placed after non-undefined values,
9070// and are followed by non-existing element. Does not change the length
9071// property.
9072// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009073RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009074 ASSERT(args.length() == 2);
9075 CONVERT_CHECKED(JSObject, object, args[0]);
9076 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9077 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009078}
9079
9080
9081// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009082RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083 ASSERT(args.length() == 2);
9084 CONVERT_CHECKED(JSArray, from, args[0]);
9085 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009086 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009087 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009088 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9089 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009090 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009091 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009092 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009093 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009094 Object* new_map;
9095 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009096 to->set_map(Map::cast(new_map));
9097 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009099 Object* obj;
9100 { MaybeObject* maybe_obj = from->ResetElements();
9101 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9102 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009103 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104 return to;
9105}
9106
9107
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009108// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009109RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009111 CONVERT_CHECKED(JSObject, object, args[0]);
9112 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009113 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009114 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009115 } else if (object->IsJSArray()) {
9116 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009118 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 }
9120}
9121
9122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009123RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009124 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009125
9126 ASSERT_EQ(3, args.length());
9127
ager@chromium.orgac091b72010-05-05 07:34:42 +00009128 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009129 Handle<Object> key1 = args.at<Object>(1);
9130 Handle<Object> key2 = args.at<Object>(2);
9131
9132 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009133 if (!key1->ToArrayIndex(&index1)
9134 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009135 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009136 }
9137
ager@chromium.orgac091b72010-05-05 07:34:42 +00009138 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9139 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009141 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 RETURN_IF_EMPTY_HANDLE(isolate,
9145 SetElement(jsobject, index1, tmp2, kStrictMode));
9146 RETURN_IF_EMPTY_HANDLE(isolate,
9147 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009149 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009150}
9151
9152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009154// might have elements. Can either return keys (positive integers) or
9155// intervals (pair of a negative integer (-start-1) followed by a
9156// positive (length)) or undefined values.
9157// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009158RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009160 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009161 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009163 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009164 // Create an array and get all the keys into it, then remove all the
9165 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009166 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167 int keys_length = keys->length();
9168 for (int i = 0; i < keys_length; i++) {
9169 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009170 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009171 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009172 // Zap invalid keys.
9173 keys->set_undefined(i);
9174 }
9175 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009176 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009178 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009181 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009182 uint32_t actual_length =
9183 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009184 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 }
9190}
9191
9192
9193// DefineAccessor takes an optional final argument which is the
9194// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9195// to the way accessors are implemented, it is set for both the getter
9196// and setter on the first call to DefineAccessor and ignored on
9197// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009198RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9200 // Compute attributes.
9201 PropertyAttributes attributes = NONE;
9202 if (args.length() == 5) {
9203 CONVERT_CHECKED(Smi, attrs, args[4]);
9204 int value = attrs->value();
9205 // Only attribute bits should be set.
9206 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9207 attributes = static_cast<PropertyAttributes>(value);
9208 }
9209
9210 CONVERT_CHECKED(JSObject, obj, args[0]);
9211 CONVERT_CHECKED(String, name, args[1]);
9212 CONVERT_CHECKED(Smi, flag, args[2]);
9213 CONVERT_CHECKED(JSFunction, fun, args[3]);
9214 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9215}
9216
9217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009218RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009219 ASSERT(args.length() == 3);
9220 CONVERT_CHECKED(JSObject, obj, args[0]);
9221 CONVERT_CHECKED(String, name, args[1]);
9222 CONVERT_CHECKED(Smi, flag, args[2]);
9223 return obj->LookupAccessor(name, flag->value() == 0);
9224}
9225
9226
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009227#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009228RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009229 ASSERT(args.length() == 0);
9230 return Execution::DebugBreakHelper();
9231}
9232
9233
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234// Helper functions for wrapping and unwrapping stack frame ids.
9235static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009236 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237 return Smi::FromInt(id >> 2);
9238}
9239
9240
9241static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9242 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9243}
9244
9245
9246// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009247// args[0]: debug event listener function to set or null or undefined for
9248// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009250RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009252 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9253 args[0]->IsUndefined() ||
9254 args[0]->IsNull());
9255 Handle<Object> callback = args.at<Object>(0);
9256 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009259 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260}
9261
9262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009263RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009264 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009265 isolate->stack_guard()->DebugBreak();
9266 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009267}
9268
9269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270static MaybeObject* DebugLookupResultValue(Heap* heap,
9271 Object* receiver,
9272 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009273 LookupResult* result,
9274 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009275 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009277 case NORMAL:
9278 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009279 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281 }
9282 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009283 case FIELD:
9284 value =
9285 JSObject::cast(
9286 result->holder())->FastPropertyAt(result->GetFieldIndex());
9287 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009289 }
9290 return value;
9291 case CONSTANT_FUNCTION:
9292 return result->GetConstantFunction();
9293 case CALLBACKS: {
9294 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009295 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009296 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009297 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009298 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009299 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009300 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009301 maybe_value = heap->isolate()->pending_exception();
9302 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009303 if (caught_exception != NULL) {
9304 *caught_exception = true;
9305 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009306 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009307 }
9308 return value;
9309 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009311 }
9312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009314 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009315 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009316 case CONSTANT_TRANSITION:
9317 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319 default:
9320 UNREACHABLE();
9321 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009322 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324}
9325
9326
ager@chromium.org32912102009-01-16 10:38:43 +00009327// Get debugger related details for an object property.
9328// args[0]: object holding property
9329// args[1]: name of the property
9330//
9331// The array returned contains the following information:
9332// 0: Property value
9333// 1: Property details
9334// 2: Property value is exception
9335// 3: Getter function if defined
9336// 4: Setter function if defined
9337// Items 2-4 are only filled if the property has either a getter or a setter
9338// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009339RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009340 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341
9342 ASSERT(args.length() == 2);
9343
9344 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9345 CONVERT_ARG_CHECKED(String, name, 1);
9346
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009347 // Make sure to set the current context to the context before the debugger was
9348 // entered (if the debugger is entered). The reason for switching context here
9349 // is that for some property lookups (accessors and interceptors) callbacks
9350 // into the embedding application can occour, and the embedding application
9351 // could have the assumption that its own global context is the current
9352 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 SaveContext save(isolate);
9354 if (isolate->debug()->InDebugger()) {
9355 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009356 }
9357
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009358 // Skip the global proxy as it has no properties and always delegates to the
9359 // real global object.
9360 if (obj->IsJSGlobalProxy()) {
9361 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9362 }
9363
9364
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365 // Check if the name is trivially convertible to an index and get the element
9366 // if so.
9367 uint32_t index;
9368 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009370 Object* element_or_char;
9371 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009373 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9374 return maybe_element_or_char;
9375 }
9376 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009377 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009379 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009380 }
9381
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009382 // Find the number of objects making up this.
9383 int length = LocalPrototypeChainLength(*obj);
9384
9385 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009386 Handle<JSObject> jsproto = obj;
9387 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009388 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009389 jsproto->LocalLookup(*name, &result);
9390 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009391 // LookupResult is not GC safe as it holds raw object pointers.
9392 // GC can happen later in this code so put the required fields into
9393 // local variables using handles when required for later use.
9394 PropertyType result_type = result.type();
9395 Handle<Object> result_callback_obj;
9396 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009397 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9398 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009399 }
9400 Smi* property_details = result.GetPropertyDetails().AsSmi();
9401 // DebugLookupResultValue can cause GC so details from LookupResult needs
9402 // to be copied to handles before this.
9403 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009404 Object* raw_value;
9405 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 DebugLookupResultValue(isolate->heap(), *obj, *name,
9407 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009408 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9409 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009411
9412 // If the callback object is a fixed array then it contains JavaScript
9413 // getter and/or setter.
9414 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9415 result_callback_obj->IsFixedArray();
9416 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009417 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009418 details->set(0, *value);
9419 details->set(1, property_details);
9420 if (hasJavaScriptAccessors) {
9421 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009422 caught_exception ? isolate->heap()->true_value()
9423 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009424 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9425 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9426 }
9427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009428 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009429 }
9430 if (i < length - 1) {
9431 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9432 }
9433 }
9434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009435 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009436}
9437
9438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009439RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009441
9442 ASSERT(args.length() == 2);
9443
9444 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9445 CONVERT_ARG_CHECKED(String, name, 1);
9446
9447 LookupResult result;
9448 obj->Lookup(*name, &result);
9449 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009452 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009453}
9454
9455
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009456// Return the property type calculated from the property details.
9457// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009458RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009459 ASSERT(args.length() == 1);
9460 CONVERT_CHECKED(Smi, details, args[0]);
9461 PropertyType type = PropertyDetails(details).type();
9462 return Smi::FromInt(static_cast<int>(type));
9463}
9464
9465
9466// Return the property attribute calculated from the property details.
9467// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009468RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009469 ASSERT(args.length() == 1);
9470 CONVERT_CHECKED(Smi, details, args[0]);
9471 PropertyAttributes attributes = PropertyDetails(details).attributes();
9472 return Smi::FromInt(static_cast<int>(attributes));
9473}
9474
9475
9476// Return the property insertion index calculated from the property details.
9477// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009478RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009479 ASSERT(args.length() == 1);
9480 CONVERT_CHECKED(Smi, details, args[0]);
9481 int index = PropertyDetails(details).index();
9482 return Smi::FromInt(index);
9483}
9484
9485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486// Return property value from named interceptor.
9487// args[0]: object
9488// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009489RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009491 ASSERT(args.length() == 2);
9492 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9493 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9494 CONVERT_ARG_CHECKED(String, name, 1);
9495
9496 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009497 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009498}
9499
9500
9501// Return element value from indexed interceptor.
9502// args[0]: object
9503// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009504RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009505 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009506 ASSERT(args.length() == 2);
9507 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9508 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9509 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9510
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009511 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009512}
9513
9514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009515RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516 ASSERT(args.length() >= 1);
9517 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009518 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009519 if (isolate->debug()->break_id() == 0 ||
9520 break_id != isolate->debug()->break_id()) {
9521 return isolate->Throw(
9522 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 }
9524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526}
9527
9528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009529RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009530 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531 ASSERT(args.length() == 1);
9532
9533 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009534 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009535 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9536 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009537 if (!maybe_result->ToObject(&result)) return maybe_result;
9538 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539
9540 // Count all frames which are relevant to debugging stack trace.
9541 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009543 if (id == StackFrame::NO_ID) {
9544 // If there is no JavaScript stack frame count is 0.
9545 return Smi::FromInt(0);
9546 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009547 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548 return Smi::FromInt(n);
9549}
9550
9551
9552static const int kFrameDetailsFrameIdIndex = 0;
9553static const int kFrameDetailsReceiverIndex = 1;
9554static const int kFrameDetailsFunctionIndex = 2;
9555static const int kFrameDetailsArgumentCountIndex = 3;
9556static const int kFrameDetailsLocalCountIndex = 4;
9557static const int kFrameDetailsSourcePositionIndex = 5;
9558static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009559static const int kFrameDetailsAtReturnIndex = 7;
9560static const int kFrameDetailsDebuggerFrameIndex = 8;
9561static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562
9563// Return an array with frame details
9564// args[0]: number: break id
9565// args[1]: number: frame index
9566//
9567// The array returned contains the following information:
9568// 0: Frame id
9569// 1: Receiver
9570// 2: Function
9571// 3: Argument count
9572// 4: Local count
9573// 5: Source position
9574// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009575// 7: Is at return
9576// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577// Arguments name, value
9578// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009579// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009580RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009581 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009582 ASSERT(args.length() == 2);
9583
9584 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009585 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009586 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9587 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009588 if (!maybe_check->ToObject(&check)) return maybe_check;
9589 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009591 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592
9593 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009595 if (id == StackFrame::NO_ID) {
9596 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009597 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009599 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009600 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601 for (; !it.done(); it.Advance()) {
9602 if (count == index) break;
9603 count++;
9604 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009605 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009607 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009608 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009609
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 // Traverse the saved contexts chain to find the active context for the
9611 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009612 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009613 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 save = save->prev();
9615 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009616 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009617
9618 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009619 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620
9621 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009623 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624
9625 // Check for constructor frame.
9626 bool constructor = it.frame()->IsConstructor();
9627
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009628 // Get scope info and read from it for local variable information.
9629 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009630 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009631 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632
9633 // Get the context.
9634 Handle<Context> context(Context::cast(it.frame()->context()));
9635
9636 // Get the locals names and values into a temporary array.
9637 //
9638 // TODO(1240907): Hide compiler-introduced stack variables
9639 // (e.g. .result)? For users of the debugger, they will probably be
9640 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009641 Handle<FixedArray> locals =
9642 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009643
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009644 // Fill in the names of the locals.
9645 for (int i = 0; i < info.NumberOfLocals(); i++) {
9646 locals->set(i * 2, *info.LocalName(i));
9647 }
9648
9649 // Fill in the values of the locals.
9650 for (int i = 0; i < info.NumberOfLocals(); i++) {
9651 if (is_optimized_frame) {
9652 // If we are inspecting an optimized frame use undefined as the
9653 // value for all locals.
9654 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009655 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009656 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009657 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009658 } else if (i < info.number_of_stack_slots()) {
9659 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009660 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9661 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009662 // Traverse the context chain to the function context as all local
9663 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009664 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009665 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009666 context = Handle<Context>(context->previous());
9667 }
9668 ASSERT(context->is_function_context());
9669 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009670 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671 }
9672 }
9673
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009674 // Check whether this frame is positioned at return. If not top
9675 // frame or if the frame is optimized it cannot be at a return.
9676 bool at_return = false;
9677 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009678 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009679 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009680
9681 // If positioned just before return find the value to be returned and add it
9682 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009683 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009684 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009685 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009686 Address internal_frame_sp = NULL;
9687 while (!it2.done()) {
9688 if (it2.frame()->is_internal()) {
9689 internal_frame_sp = it2.frame()->sp();
9690 } else {
9691 if (it2.frame()->is_java_script()) {
9692 if (it2.frame()->id() == it.frame()->id()) {
9693 // The internal frame just before the JavaScript frame contains the
9694 // value to return on top. A debug break at return will create an
9695 // internal frame to store the return value (eax/rax/r0) before
9696 // entering the debug break exit frame.
9697 if (internal_frame_sp != NULL) {
9698 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009699 Handle<Object>(Memory::Object_at(internal_frame_sp),
9700 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009701 break;
9702 }
9703 }
9704 }
9705
9706 // Indicate that the previous frame was not an internal frame.
9707 internal_frame_sp = NULL;
9708 }
9709 it2.Advance();
9710 }
9711 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712
9713 // Now advance to the arguments adapter frame (if any). It contains all
9714 // the provided parameters whereas the function frame always have the number
9715 // of arguments matching the functions parameters. The rest of the
9716 // information (except for what is collected above) is the same.
9717 it.AdvanceToArgumentsFrame();
9718
9719 // Find the number of arguments to fill. At least fill the number of
9720 // parameters for the function and fill more if more parameters are provided.
9721 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009722 if (argument_count < it.frame()->ComputeParametersCount()) {
9723 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009724 }
9725
9726 // Calculate the size of the result.
9727 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009728 2 * (argument_count + info.NumberOfLocals()) +
9729 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009730 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009731
9732 // Add the frame id.
9733 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9734
9735 // Add the function (same as in function frame).
9736 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9737
9738 // Add the arguments count.
9739 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9740
9741 // Add the locals count
9742 details->set(kFrameDetailsLocalCountIndex,
9743 Smi::FromInt(info.NumberOfLocals()));
9744
9745 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009746 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009747 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9748 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009749 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009750 }
9751
9752 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009755 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009756 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009758 // Add information on whether this frame is invoked in the debugger context.
9759 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009760 heap->ToBoolean(*save->context() ==
9761 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762
9763 // Fill the dynamic part.
9764 int details_index = kFrameDetailsFirstDynamicIndex;
9765
9766 // Add arguments name and value.
9767 for (int i = 0; i < argument_count; i++) {
9768 // Name of the argument.
9769 if (i < info.number_of_parameters()) {
9770 details->set(details_index++, *info.parameter_name(i));
9771 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773 }
9774
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009775 // Parameter value. If we are inspecting an optimized frame, use
9776 // undefined as the value.
9777 //
9778 // TODO(3141533): We should be able to get the actual parameter
9779 // value for optimized frames.
9780 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009781 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 details->set(details_index++, it.frame()->GetParameter(i));
9783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009784 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785 }
9786 }
9787
9788 // Add locals name and value from the temporary copy from the function frame.
9789 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9790 details->set(details_index++, locals->get(i));
9791 }
9792
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009793 // Add the value being returned.
9794 if (at_return) {
9795 details->set(details_index++, *return_value);
9796 }
9797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009798 // Add the receiver (same as in function frame).
9799 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9800 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009801 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802 if (!receiver->IsJSObject()) {
9803 // If the receiver is NOT a JSObject we have hit an optimization
9804 // where a value object is not converted into a wrapped JS objects.
9805 // To hide this optimization from the debugger, we wrap the receiver
9806 // by creating correct wrapper object based on the calling frame's
9807 // global context.
9808 it.Advance();
9809 Handle<Context> calling_frames_global_context(
9810 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009811 receiver =
9812 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009813 }
9814 details->set(kFrameDetailsReceiverIndex, *receiver);
9815
9816 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818}
9819
9820
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009821// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009822static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009823 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009824 Handle<SerializedScopeInfo> serialized_scope_info,
9825 ScopeInfo<>& scope_info,
9826 Handle<Context> context,
9827 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009828 // Fill all context locals to the context extension.
9829 for (int i = Context::MIN_CONTEXT_SLOTS;
9830 i < scope_info.number_of_context_slots();
9831 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009832 int context_index = serialized_scope_info->ContextSlotIndex(
9833 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009834
9835 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009836 if (*scope_info.context_slot_name(i) !=
9837 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009838 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009840 SetProperty(scope_object,
9841 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009842 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009843 NONE,
9844 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009845 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009846 }
9847 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009848
9849 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009850}
9851
9852
9853// Create a plain JSObject which materializes the local scope for the specified
9854// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9856 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009857 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009858 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009859 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9860 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009861
9862 // Allocate and initialize a JSObject with all the arguments, stack locals
9863 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009864 Handle<JSObject> local_scope =
9865 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009866
9867 // First fill all parameters.
9868 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009869 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009870 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009871 SetProperty(local_scope,
9872 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009873 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009874 NONE,
9875 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009876 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009877 }
9878
9879 // Second fill all stack locals.
9880 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009881 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009883 SetProperty(local_scope,
9884 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009885 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009886 NONE,
9887 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009888 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009889 }
9890
9891 // Third fill all context locals.
9892 Handle<Context> frame_context(Context::cast(frame->context()));
9893 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009894 if (!CopyContextLocalsToScopeObject(isolate,
9895 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009896 function_context, local_scope)) {
9897 return Handle<JSObject>();
9898 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009899
9900 // Finally copy any properties from the function context extension. This will
9901 // be variables introduced by eval.
9902 if (function_context->closure() == *function) {
9903 if (function_context->has_extension() &&
9904 !function_context->IsGlobalContext()) {
9905 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009906 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009907 for (int i = 0; i < keys->length(); i++) {
9908 // Names of variables introduced by eval are strings.
9909 ASSERT(keys->get(i)->IsString());
9910 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009911 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009912 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009913 SetProperty(local_scope,
9914 key,
9915 GetProperty(ext, key),
9916 NONE,
9917 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009918 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009919 }
9920 }
9921 }
9922 return local_scope;
9923}
9924
9925
9926// Create a plain JSObject which materializes the closure content for the
9927// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9929 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009930 ASSERT(context->is_function_context());
9931
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009932 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009933 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9934 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009935
9936 // Allocate and initialize a JSObject with all the content of theis function
9937 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 Handle<JSObject> closure_scope =
9939 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009940
9941 // Check whether the arguments shadow object exists.
9942 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 shared->scope_info()->ContextSlotIndex(
9944 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009945 if (arguments_shadow_index >= 0) {
9946 // In this case all the arguments are available in the arguments shadow
9947 // object.
9948 Handle<JSObject> arguments_shadow(
9949 JSObject::cast(context->get(arguments_shadow_index)));
9950 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009951 // We don't expect exception-throwing getters on the arguments shadow.
9952 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009953 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009954 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009955 SetProperty(closure_scope,
9956 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009957 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009958 NONE,
9959 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009960 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009961 }
9962 }
9963
9964 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009965 if (!CopyContextLocalsToScopeObject(isolate,
9966 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009967 context, closure_scope)) {
9968 return Handle<JSObject>();
9969 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009970
9971 // Finally copy any properties from the function context extension. This will
9972 // be variables introduced by eval.
9973 if (context->has_extension()) {
9974 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009975 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009976 for (int i = 0; i < keys->length(); i++) {
9977 // Names of variables introduced by eval are strings.
9978 ASSERT(keys->get(i)->IsString());
9979 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 RETURN_IF_EMPTY_HANDLE_VALUE(
9981 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009982 SetProperty(closure_scope,
9983 key,
9984 GetProperty(ext, key),
9985 NONE,
9986 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009987 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009988 }
9989 }
9990
9991 return closure_scope;
9992}
9993
9994
9995// Iterate over the actual scopes visible from a stack frame. All scopes are
9996// backed by an actual context except the local scope, which is inserted
9997// "artifically" in the context chain.
9998class ScopeIterator {
9999 public:
10000 enum ScopeType {
10001 ScopeTypeGlobal = 0,
10002 ScopeTypeLocal,
10003 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010004 ScopeTypeClosure,
10005 // Every catch block contains an implicit with block (its parameter is
10006 // a JSContextExtensionObject) that extends current scope with a variable
10007 // holding exception object. Such with blocks are treated as scopes of their
10008 // own type.
10009 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010010 };
10011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010012 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10013 : isolate_(isolate),
10014 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010015 function_(JSFunction::cast(frame->function())),
10016 context_(Context::cast(frame->context())),
10017 local_done_(false),
10018 at_local_(false) {
10019
10020 // Check whether the first scope is actually a local scope.
10021 if (context_->IsGlobalContext()) {
10022 // If there is a stack slot for .result then this local scope has been
10023 // created for evaluating top level code and it is not a real local scope.
10024 // Checking for the existence of .result seems fragile, but the scope info
10025 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010026 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010027 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010028 at_local_ = index < 0;
10029 } else if (context_->is_function_context()) {
10030 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010031 } else if (context_->closure() != *function_) {
10032 // The context_ is a with block from the outer function.
10033 ASSERT(context_->has_extension());
10034 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010035 }
10036 }
10037
10038 // More scopes?
10039 bool Done() { return context_.is_null(); }
10040
10041 // Move to the next scope.
10042 void Next() {
10043 // If at a local scope mark the local scope as passed.
10044 if (at_local_) {
10045 at_local_ = false;
10046 local_done_ = true;
10047
10048 // If the current context is not associated with the local scope the
10049 // current context is the next real scope, so don't move to the next
10050 // context in this case.
10051 if (context_->closure() != *function_) {
10052 return;
10053 }
10054 }
10055
10056 // The global scope is always the last in the chain.
10057 if (context_->IsGlobalContext()) {
10058 context_ = Handle<Context>();
10059 return;
10060 }
10061
10062 // Move to the next context.
10063 if (context_->is_function_context()) {
10064 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10065 } else {
10066 context_ = Handle<Context>(context_->previous());
10067 }
10068
10069 // If passing the local scope indicate that the current scope is now the
10070 // local scope.
10071 if (!local_done_ &&
10072 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10073 at_local_ = true;
10074 }
10075 }
10076
10077 // Return the type of the current scope.
10078 int Type() {
10079 if (at_local_) {
10080 return ScopeTypeLocal;
10081 }
10082 if (context_->IsGlobalContext()) {
10083 ASSERT(context_->global()->IsGlobalObject());
10084 return ScopeTypeGlobal;
10085 }
10086 if (context_->is_function_context()) {
10087 return ScopeTypeClosure;
10088 }
10089 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010090 // Current scope is either an explicit with statement or a with statement
10091 // implicitely generated for a catch block.
10092 // If the extension object here is a JSContextExtensionObject then
10093 // current with statement is one frome a catch block otherwise it's a
10094 // regular with statement.
10095 if (context_->extension()->IsJSContextExtensionObject()) {
10096 return ScopeTypeCatch;
10097 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010098 return ScopeTypeWith;
10099 }
10100
10101 // Return the JavaScript object with the content of the current scope.
10102 Handle<JSObject> ScopeObject() {
10103 switch (Type()) {
10104 case ScopeIterator::ScopeTypeGlobal:
10105 return Handle<JSObject>(CurrentContext()->global());
10106 break;
10107 case ScopeIterator::ScopeTypeLocal:
10108 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010110 break;
10111 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010112 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010113 // Return the with object.
10114 return Handle<JSObject>(CurrentContext()->extension());
10115 break;
10116 case ScopeIterator::ScopeTypeClosure:
10117 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010119 break;
10120 }
10121 UNREACHABLE();
10122 return Handle<JSObject>();
10123 }
10124
10125 // Return the context for this scope. For the local context there might not
10126 // be an actual context.
10127 Handle<Context> CurrentContext() {
10128 if (at_local_ && context_->closure() != *function_) {
10129 return Handle<Context>();
10130 }
10131 return context_;
10132 }
10133
10134#ifdef DEBUG
10135 // Debug print of the content of the current scope.
10136 void DebugPrint() {
10137 switch (Type()) {
10138 case ScopeIterator::ScopeTypeGlobal:
10139 PrintF("Global:\n");
10140 CurrentContext()->Print();
10141 break;
10142
10143 case ScopeIterator::ScopeTypeLocal: {
10144 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010145 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010146 scope_info.Print();
10147 if (!CurrentContext().is_null()) {
10148 CurrentContext()->Print();
10149 if (CurrentContext()->has_extension()) {
10150 Handle<JSObject> extension =
10151 Handle<JSObject>(CurrentContext()->extension());
10152 if (extension->IsJSContextExtensionObject()) {
10153 extension->Print();
10154 }
10155 }
10156 }
10157 break;
10158 }
10159
10160 case ScopeIterator::ScopeTypeWith: {
10161 PrintF("With:\n");
10162 Handle<JSObject> extension =
10163 Handle<JSObject>(CurrentContext()->extension());
10164 extension->Print();
10165 break;
10166 }
10167
ager@chromium.orga1645e22009-09-09 19:27:10 +000010168 case ScopeIterator::ScopeTypeCatch: {
10169 PrintF("Catch:\n");
10170 Handle<JSObject> extension =
10171 Handle<JSObject>(CurrentContext()->extension());
10172 extension->Print();
10173 break;
10174 }
10175
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010176 case ScopeIterator::ScopeTypeClosure: {
10177 PrintF("Closure:\n");
10178 CurrentContext()->Print();
10179 if (CurrentContext()->has_extension()) {
10180 Handle<JSObject> extension =
10181 Handle<JSObject>(CurrentContext()->extension());
10182 if (extension->IsJSContextExtensionObject()) {
10183 extension->Print();
10184 }
10185 }
10186 break;
10187 }
10188
10189 default:
10190 UNREACHABLE();
10191 }
10192 PrintF("\n");
10193 }
10194#endif
10195
10196 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010197 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010198 JavaScriptFrame* frame_;
10199 Handle<JSFunction> function_;
10200 Handle<Context> context_;
10201 bool local_done_;
10202 bool at_local_;
10203
10204 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10205};
10206
10207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010208RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010210 ASSERT(args.length() == 2);
10211
10212 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010213 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010214 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10215 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010216 if (!maybe_check->ToObject(&check)) return maybe_check;
10217 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010218 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10219
10220 // Get the frame where the debugging is performed.
10221 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010222 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010223 JavaScriptFrame* frame = it.frame();
10224
10225 // Count the visible scopes.
10226 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010228 n++;
10229 }
10230
10231 return Smi::FromInt(n);
10232}
10233
10234
10235static const int kScopeDetailsTypeIndex = 0;
10236static const int kScopeDetailsObjectIndex = 1;
10237static const int kScopeDetailsSize = 2;
10238
10239// Return an array with scope details
10240// args[0]: number: break id
10241// args[1]: number: frame index
10242// args[2]: number: scope index
10243//
10244// The array returned contains the following information:
10245// 0: Scope type
10246// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010247RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010248 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010249 ASSERT(args.length() == 3);
10250
10251 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010252 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010253 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10254 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010255 if (!maybe_check->ToObject(&check)) return maybe_check;
10256 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010257 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10258 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10259
10260 // Get the frame where the debugging is performed.
10261 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010262 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010263 JavaScriptFrame* frame = frame_it.frame();
10264
10265 // Find the requested scope.
10266 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010267 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010268 for (; !it.Done() && n < index; it.Next()) {
10269 n++;
10270 }
10271 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010272 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010273 }
10274
10275 // Calculate the size of the result.
10276 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010277 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010278
10279 // Fill in scope details.
10280 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010281 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010283 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010286}
10287
10288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010289RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010290 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010291 ASSERT(args.length() == 0);
10292
10293#ifdef DEBUG
10294 // Print the scopes for the top frame.
10295 StackFrameLocator locator;
10296 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010297 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010298 it.DebugPrint();
10299 }
10300#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010301 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010302}
10303
10304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010305RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010306 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010307 ASSERT(args.length() == 1);
10308
10309 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010310 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010311 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10312 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010313 if (!maybe_result->ToObject(&result)) return maybe_result;
10314 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010315
10316 // Count all archived V8 threads.
10317 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318 for (ThreadState* thread =
10319 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010320 thread != NULL;
10321 thread = thread->Next()) {
10322 n++;
10323 }
10324
10325 // Total number of threads is current thread and archived threads.
10326 return Smi::FromInt(n + 1);
10327}
10328
10329
10330static const int kThreadDetailsCurrentThreadIndex = 0;
10331static const int kThreadDetailsThreadIdIndex = 1;
10332static const int kThreadDetailsSize = 2;
10333
10334// Return an array with thread details
10335// args[0]: number: break id
10336// args[1]: number: thread index
10337//
10338// The array returned contains the following information:
10339// 0: Is current thread?
10340// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010341RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010343 ASSERT(args.length() == 2);
10344
10345 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010346 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010347 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10348 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010349 if (!maybe_check->ToObject(&check)) return maybe_check;
10350 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010351 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10352
10353 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 Handle<FixedArray> details =
10355 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010356
10357 // Thread index 0 is current thread.
10358 if (index == 0) {
10359 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360 details->set(kThreadDetailsCurrentThreadIndex,
10361 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010362 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010363 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010364 } else {
10365 // Find the thread with the requested index.
10366 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 ThreadState* thread =
10368 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010369 while (index != n && thread != NULL) {
10370 thread = thread->Next();
10371 n++;
10372 }
10373 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010375 }
10376
10377 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010378 details->set(kThreadDetailsCurrentThreadIndex,
10379 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010380 details->set(kThreadDetailsThreadIdIndex,
10381 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010382 }
10383
10384 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010386}
10387
10388
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010389// Sets the disable break state
10390// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010391RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010392 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010393 ASSERT(args.length() == 1);
10394 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 isolate->debug()->set_disable_break(disable_break);
10396 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010397}
10398
10399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010400RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010401 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402 ASSERT(args.length() == 1);
10403
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010404 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10405 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406 // Find the number of break points
10407 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010410 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 Handle<FixedArray>::cast(break_locations));
10412}
10413
10414
10415// Set a break point in a function
10416// args[0]: function
10417// args[1]: number: break source position (within the function source)
10418// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010419RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010420 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010422 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10423 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010424 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10425 RUNTIME_ASSERT(source_position >= 0);
10426 Handle<Object> break_point_object_arg = args.at<Object>(2);
10427
10428 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010429 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10430 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010431
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010432 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433}
10434
10435
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010436Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10437 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010438 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 // Iterate the heap looking for SharedFunctionInfo generated from the
10440 // script. The inner most SharedFunctionInfo containing the source position
10441 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010442 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010443 // which is found is not compiled it is compiled and the heap is iterated
10444 // again as the compilation might create inner functions from the newly
10445 // compiled function and the actual requested break point might be in one of
10446 // these functions.
10447 bool done = false;
10448 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010449 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010450 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 while (!done) {
10452 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010453 for (HeapObject* obj = iterator.next();
10454 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 if (obj->IsSharedFunctionInfo()) {
10456 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10457 if (shared->script() == *script) {
10458 // If the SharedFunctionInfo found has the requested script data and
10459 // contains the source position it is a candidate.
10460 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010461 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010462 start_position = shared->start_position();
10463 }
10464 if (start_position <= position &&
10465 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010466 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467 // candidate this is the new candidate.
10468 if (target.is_null()) {
10469 target_start_position = start_position;
10470 target = shared;
10471 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010472 if (target_start_position == start_position &&
10473 shared->end_position() == target->end_position()) {
10474 // If a top-level function contain only one function
10475 // declartion the source for the top-level and the function is
10476 // the same. In that case prefer the non top-level function.
10477 if (!shared->is_toplevel()) {
10478 target_start_position = start_position;
10479 target = shared;
10480 }
10481 } else if (target_start_position <= start_position &&
10482 shared->end_position() <= target->end_position()) {
10483 // This containment check includes equality as a function inside
10484 // a top-level function can share either start or end position
10485 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 target_start_position = start_position;
10487 target = shared;
10488 }
10489 }
10490 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 }
10492 }
10493 }
10494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497 }
10498
10499 // If the candidate found is compiled we are done. NOTE: when lazy
10500 // compilation of inner functions is introduced some additional checking
10501 // needs to be done here to compile inner functions.
10502 done = target->is_compiled();
10503 if (!done) {
10504 // If the candidate is not compiled compile it to reveal any inner
10505 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010506 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 }
10508 }
10509
10510 return *target;
10511}
10512
10513
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010514// Changes the state of a break point in a script and returns source position
10515// where break point was set. NOTE: Regarding performance see the NOTE for
10516// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517// args[0]: script to set break point in
10518// args[1]: number: break source position (within the script source)
10519// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010520RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010521 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010522 ASSERT(args.length() == 3);
10523 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10524 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10525 RUNTIME_ASSERT(source_position >= 0);
10526 Handle<Object> break_point_object_arg = args.at<Object>(2);
10527
10528 // Get the script from the script wrapper.
10529 RUNTIME_ASSERT(wrapper->value()->IsScript());
10530 Handle<Script> script(Script::cast(wrapper->value()));
10531
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010532 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 if (!result->IsUndefined()) {
10535 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10536 // Find position within function. The script position might be before the
10537 // source position of the first function.
10538 int position;
10539 if (shared->start_position() > source_position) {
10540 position = 0;
10541 } else {
10542 position = source_position - shared->start_position();
10543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010545 position += shared->start_position();
10546 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010547 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010548 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549}
10550
10551
10552// Clear a break point
10553// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010554RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010555 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 ASSERT(args.length() == 1);
10557 Handle<Object> break_point_object_arg = args.at<Object>(0);
10558
10559 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010562 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563}
10564
10565
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010566// Change the state of break on exceptions.
10567// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10568// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010569RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010572 RUNTIME_ASSERT(args[0]->IsNumber());
10573 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010575 // If the number doesn't match an enum value, the ChangeBreakOnException
10576 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577 ExceptionBreakType type =
10578 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010579 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 isolate->debug()->ChangeBreakOnException(type, enable);
10581 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582}
10583
10584
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010585// Returns the state of break on exceptions
10586// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010587RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010589 ASSERT(args.length() == 1);
10590 RUNTIME_ASSERT(args[0]->IsNumber());
10591
10592 ExceptionBreakType type =
10593 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010594 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010595 return Smi::FromInt(result);
10596}
10597
10598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599// Prepare for stepping
10600// args[0]: break id for checking execution state
10601// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010602// args[2]: number of times to perform the step, for step out it is the number
10603// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010604RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606 ASSERT(args.length() == 3);
10607 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010608 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010609 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10610 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010611 if (!maybe_check->ToObject(&check)) return maybe_check;
10612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 }
10616
10617 // Get the step action and check validity.
10618 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10619 if (step_action != StepIn &&
10620 step_action != StepNext &&
10621 step_action != StepOut &&
10622 step_action != StepInMin &&
10623 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010624 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625 }
10626
10627 // Get the number of steps.
10628 int step_count = NumberToInt32(args[2]);
10629 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010630 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631 }
10632
ager@chromium.orga1645e22009-09-09 19:27:10 +000010633 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010634 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10638 step_count);
10639 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640}
10641
10642
10643// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010644RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010646 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010647 isolate->debug()->ClearStepping();
10648 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649}
10650
10651
10652// Creates a copy of the with context chain. The copy of the context chain is
10653// is linked to the function context supplied.
10654static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10655 Handle<Context> function_context) {
10656 // At the bottom of the chain. Return the function context to link to.
10657 if (context_chain->is_function_context()) {
10658 return function_context;
10659 }
10660
10661 // Recursively copy the with contexts.
10662 Handle<Context> previous(context_chain->previous());
10663 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010664 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010665 return context->GetIsolate()->factory()->NewWithContext(
10666 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667}
10668
10669
10670// Helper function to find or create the arguments object for
10671// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010672static Handle<Object> GetArgumentsObject(Isolate* isolate,
10673 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010675 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676 const ScopeInfo<>* sinfo,
10677 Handle<Context> function_context) {
10678 // Try to find the value of 'arguments' to pass as parameter. If it is not
10679 // found (that is the debugged function does not reference 'arguments' and
10680 // does not support eval) then create an 'arguments' object.
10681 int index;
10682 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010683 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010684 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010685 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010686 }
10687 }
10688
10689 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010690 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10691 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010694 }
10695 }
10696
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010697 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010698 Handle<JSObject> arguments =
10699 isolate->factory()->NewArgumentsObject(function, length);
10700 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010701
10702 AssertNoAllocation no_gc;
10703 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010705 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010707 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708 return arguments;
10709}
10710
10711
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712static const char kSourceStr[] =
10713 "(function(arguments,__source__){return eval(__source__);})";
10714
10715
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010717// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718// extension part has all the parameters and locals of the function on the
10719// stack frame. A function which calls eval with the code to evaluate is then
10720// compiled in this context and called in this context. As this context
10721// replaces the context of the function on the stack frame a new (empty)
10722// function is created as well to be used as the closure for the context.
10723// This function and the context acts as replacements for the function on the
10724// stack frame presenting the same view of the values of parameters and
10725// local variables as if the piece of JavaScript was evaluated at the point
10726// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010727RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010728 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729
10730 // Check the execution state and decode arguments frame and source to be
10731 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010732 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010733 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010734 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10735 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010736 if (!maybe_check_result->ToObject(&check_result)) {
10737 return maybe_check_result;
10738 }
10739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10741 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010742 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010743 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010744
10745 // Handle the processing of break.
10746 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747
10748 // Get the frame where the debugging is performed.
10749 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010750 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 JavaScriptFrame* frame = it.frame();
10752 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010753 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010754 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755
10756 // Traverse the saved contexts chain to find the active context for the
10757 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010759 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 save = save->prev();
10761 }
10762 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 SaveContext savex(isolate);
10764 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010765
10766 // Create the (empty) function replacing the function on the stack frame for
10767 // the purpose of evaluating in the context created below. It is important
10768 // that this function does not describe any parameters and local variables
10769 // in the context. If it does then this will cause problems with the lookup
10770 // in Context::Lookup, where context slots for parameters and local variables
10771 // are looked at before the extension object.
10772 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010773 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10774 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 go_between->set_context(function->context());
10776#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010777 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10779 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10780#endif
10781
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010782 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010783 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10784 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785
10786 // Allocate a new context for the debug evaluation and set the extension
10787 // object build.
10788 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010789 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10790 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010791 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010792 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010793 Handle<Context> frame_context(Context::cast(frame->context()));
10794 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795 context = CopyWithContextChain(frame_context, context);
10796
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010797 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010798 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010799 Handle<JSObject>::cast(additional_context), false);
10800 }
10801
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802 // Wrap the evaluation statement in a new function compiled in the newly
10803 // created context. The function has one parameter which has to be called
10804 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010805 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010808 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 isolate->factory()->NewStringFromAscii(
10810 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010811
10812 // Currently, the eval code will be executed in non-strict mode,
10813 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010814 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010815 Compiler::CompileEval(function_source,
10816 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010817 context->IsGlobalContext(),
10818 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010819 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010821 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822
10823 // Invoke the result of the compilation to get the evaluation function.
10824 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010826 Handle<Object> evaluation_function =
10827 Execution::Call(compiled_function, receiver, 0, NULL,
10828 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010829 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10832 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010833 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834
10835 // Invoke the evaluation function and return the result.
10836 const int argc = 2;
10837 Object** argv[argc] = { arguments.location(),
10838 Handle<Object>::cast(source).location() };
10839 Handle<Object> result =
10840 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10841 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010842 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010843
10844 // Skip the global proxy as it has no properties and always delegates to the
10845 // real global object.
10846 if (result->IsJSGlobalProxy()) {
10847 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10848 }
10849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850 return *result;
10851}
10852
10853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010854RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856
10857 // Check the execution state and decode arguments frame and source to be
10858 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010859 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010860 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010861 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10862 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010863 if (!maybe_check_result->ToObject(&check_result)) {
10864 return maybe_check_result;
10865 }
10866 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010868 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010869 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010870
10871 // Handle the processing of break.
10872 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
10874 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010875 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010876 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010877 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878 top = top->prev();
10879 }
10880 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010881 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010882 }
10883
10884 // Get the global context now set to the top context from before the
10885 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010886 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010887
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010888 bool is_global = true;
10889
10890 if (additional_context->IsJSObject()) {
10891 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010892 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10893 isolate->factory()->empty_string(),
10894 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010895 go_between->set_context(*context);
10896 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010897 isolate->factory()->NewFunctionContext(
10898 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010899 context->set_extension(JSObject::cast(*additional_context));
10900 is_global = false;
10901 }
10902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010904 // Currently, the eval code will be executed in non-strict mode,
10905 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010906 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010907 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010908 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010910 Handle<JSFunction>(
10911 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10912 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010913
10914 // Invoke the result of the compilation to get the evaluation function.
10915 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010916 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 Handle<Object> result =
10918 Execution::Call(compiled_function, receiver, 0, NULL,
10919 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010920 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010921 return *result;
10922}
10923
10924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010925RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010927 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010929 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010930 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931
10932 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010933 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010934 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10935 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10936 // because using
10937 // instances->set(i, *GetScriptWrapper(script))
10938 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10939 // already have deferenced the instances handle.
10940 Handle<JSValue> wrapper = GetScriptWrapper(script);
10941 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010942 }
10943
10944 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 Handle<JSObject> result =
10946 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 Handle<JSArray>::cast(result)->SetContent(*instances);
10948 return *result;
10949}
10950
10951
10952// Helper function used by Runtime_DebugReferencedBy below.
10953static int DebugReferencedBy(JSObject* target,
10954 Object* instance_filter, int max_references,
10955 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956 JSFunction* arguments_function) {
10957 NoHandleAllocation ha;
10958 AssertNoAllocation no_alloc;
10959
10960 // Iterate the heap.
10961 int count = 0;
10962 JSObject* last = NULL;
10963 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010964 HeapObject* heap_obj = NULL;
10965 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966 (max_references == 0 || count < max_references)) {
10967 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 if (heap_obj->IsJSObject()) {
10969 // Skip context extension objects and argument arrays as these are
10970 // checked in the context of functions using them.
10971 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010972 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 obj->map()->constructor() == arguments_function) {
10974 continue;
10975 }
10976
10977 // Check if the JS object has a reference to the object looked for.
10978 if (obj->ReferencesObject(target)) {
10979 // Check instance filter if supplied. This is normally used to avoid
10980 // references from mirror objects (see Runtime_IsInPrototypeChain).
10981 if (!instance_filter->IsUndefined()) {
10982 Object* V = obj;
10983 while (true) {
10984 Object* prototype = V->GetPrototype();
10985 if (prototype->IsNull()) {
10986 break;
10987 }
10988 if (instance_filter == prototype) {
10989 obj = NULL; // Don't add this object.
10990 break;
10991 }
10992 V = prototype;
10993 }
10994 }
10995
10996 if (obj != NULL) {
10997 // Valid reference found add to instance array if supplied an update
10998 // count.
10999 if (instances != NULL && count < instances_size) {
11000 instances->set(count, obj);
11001 }
11002 last = obj;
11003 count++;
11004 }
11005 }
11006 }
11007 }
11008
11009 // Check for circular reference only. This can happen when the object is only
11010 // referenced from mirrors and has a circular reference in which case the
11011 // object is not really alive and would have been garbage collected if not
11012 // referenced from the mirror.
11013 if (count == 1 && last == target) {
11014 count = 0;
11015 }
11016
11017 // Return the number of referencing objects found.
11018 return count;
11019}
11020
11021
11022// Scan the heap for objects with direct references to an object
11023// args[0]: the object to find references to
11024// args[1]: constructor function for instances to exclude (Mirror)
11025// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011026RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011027 ASSERT(args.length() == 3);
11028
11029 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011030 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011031
11032 // Check parameters.
11033 CONVERT_CHECKED(JSObject, target, args[0]);
11034 Object* instance_filter = args[1];
11035 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11036 instance_filter->IsJSObject());
11037 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11038 RUNTIME_ASSERT(max_references >= 0);
11039
11040 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011041 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 JSFunction* arguments_function =
11044 JSFunction::cast(arguments_boilerplate->map()->constructor());
11045
11046 // Get the number of referencing objects.
11047 int count;
11048 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011049 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050
11051 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011052 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011054 if (!maybe_object->ToObject(&object)) return maybe_object;
11055 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011056 FixedArray* instances = FixedArray::cast(object);
11057
11058 // Fill the referencing objects.
11059 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011060 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061
11062 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011063 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11065 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011066 if (!maybe_result->ToObject(&result)) return maybe_result;
11067 }
11068 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011069 return result;
11070}
11071
11072
11073// Helper function used by Runtime_DebugConstructedBy below.
11074static int DebugConstructedBy(JSFunction* constructor, int max_references,
11075 FixedArray* instances, int instances_size) {
11076 AssertNoAllocation no_alloc;
11077
11078 // Iterate the heap.
11079 int count = 0;
11080 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011081 HeapObject* heap_obj = NULL;
11082 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011083 (max_references == 0 || count < max_references)) {
11084 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085 if (heap_obj->IsJSObject()) {
11086 JSObject* obj = JSObject::cast(heap_obj);
11087 if (obj->map()->constructor() == constructor) {
11088 // Valid reference found add to instance array if supplied an update
11089 // count.
11090 if (instances != NULL && count < instances_size) {
11091 instances->set(count, obj);
11092 }
11093 count++;
11094 }
11095 }
11096 }
11097
11098 // Return the number of referencing objects found.
11099 return count;
11100}
11101
11102
11103// Scan the heap for objects constructed by a specific function.
11104// args[0]: the constructor to find instances of
11105// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011106RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011107 ASSERT(args.length() == 2);
11108
11109 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011111
11112 // Check parameters.
11113 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11114 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11115 RUNTIME_ASSERT(max_references >= 0);
11116
11117 // Get the number of referencing objects.
11118 int count;
11119 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11120
11121 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011122 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011124 if (!maybe_object->ToObject(&object)) return maybe_object;
11125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126 FixedArray* instances = FixedArray::cast(object);
11127
11128 // Fill the referencing objects.
11129 count = DebugConstructedBy(constructor, max_references, instances, count);
11130
11131 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011132 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11134 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011135 if (!maybe_result->ToObject(&result)) return maybe_result;
11136 }
11137 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 return result;
11139}
11140
11141
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011142// Find the effective prototype object as returned by __proto__.
11143// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011144RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145 ASSERT(args.length() == 1);
11146
11147 CONVERT_CHECKED(JSObject, obj, args[0]);
11148
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011149 // Use the __proto__ accessor.
11150 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011151}
11152
11153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011154RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011155 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011156 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011157 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011158}
11159
11160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011161RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011162#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011163 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011164 ASSERT(args.length() == 1);
11165 // Get the function and make sure it is compiled.
11166 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011167 Handle<SharedFunctionInfo> shared(func->shared());
11168 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011169 return Failure::Exception();
11170 }
11171 func->code()->PrintLn();
11172#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011173 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011174}
ager@chromium.org9085a012009-05-11 19:22:57 +000011175
11176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011177RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011178#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011179 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011180 ASSERT(args.length() == 1);
11181 // Get the function and make sure it is compiled.
11182 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011183 Handle<SharedFunctionInfo> shared(func->shared());
11184 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011185 return Failure::Exception();
11186 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011187 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011188#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011189 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011190}
11191
11192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011193RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011194 NoHandleAllocation ha;
11195 ASSERT(args.length() == 1);
11196
11197 CONVERT_CHECKED(JSFunction, f, args[0]);
11198 return f->shared()->inferred_name();
11199}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011200
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011201
11202static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011204 AssertNoAllocation no_allocations;
11205
11206 int counter = 0;
11207 int buffer_size = buffer->length();
11208 HeapIterator iterator;
11209 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11210 ASSERT(obj != NULL);
11211 if (!obj->IsSharedFunctionInfo()) {
11212 continue;
11213 }
11214 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11215 if (shared->script() != script) {
11216 continue;
11217 }
11218 if (counter < buffer_size) {
11219 buffer->set(counter, shared);
11220 }
11221 counter++;
11222 }
11223 return counter;
11224}
11225
11226// For a script finds all SharedFunctionInfo's in the heap that points
11227// to this script. Returns JSArray of SharedFunctionInfo wrapped
11228// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011229RUNTIME_FUNCTION(MaybeObject*,
11230 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011231 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011232 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011233 CONVERT_CHECKED(JSValue, script_value, args[0]);
11234
11235 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11236
11237 const int kBufferSize = 32;
11238
11239 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011240 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011241 int number = FindSharedFunctionInfosForScript(*script, *array);
11242 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011244 FindSharedFunctionInfosForScript(*script, *array);
11245 }
11246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011248 result->set_length(Smi::FromInt(number));
11249
11250 LiveEdit::WrapSharedFunctionInfos(result);
11251
11252 return *result;
11253}
11254
11255// For a script calculates compilation information about all its functions.
11256// The script source is explicitly specified by the second argument.
11257// The source of the actual script is not used, however it is important that
11258// all generated code keeps references to this particular instance of script.
11259// Returns a JSArray of compilation infos. The array is ordered so that
11260// each function with all its descendant is always stored in a continues range
11261// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011262RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011263 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011264 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011265 CONVERT_CHECKED(JSValue, script, args[0]);
11266 CONVERT_ARG_CHECKED(String, source, 1);
11267 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11268
11269 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11270
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011271 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011272 return Failure::Exception();
11273 }
11274
11275 return result;
11276}
11277
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011278// Changes the source of the script to a new_source.
11279// If old_script_name is provided (i.e. is a String), also creates a copy of
11280// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011281RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011282 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011284 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11285 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011286 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011287
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011288 CONVERT_CHECKED(Script, original_script_pointer,
11289 original_script_value->value());
11290 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011291
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011292 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11293 new_source,
11294 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011295
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011296 if (old_script->IsScript()) {
11297 Handle<Script> script_handle(Script::cast(old_script));
11298 return *(GetScriptWrapper(script_handle));
11299 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011300 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011301 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011302}
11303
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011305RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011306 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011308 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11309 return LiveEdit::FunctionSourceUpdated(shared_info);
11310}
11311
11312
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011313// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011314RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011315 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011316 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011317 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11318 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11319
ager@chromium.orgac091b72010-05-05 07:34:42 +000011320 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011321}
11322
11323// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011324RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011325 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 HandleScope scope(isolate);
11327 Handle<Object> function_object(args[0], isolate);
11328 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011329
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011330 if (function_object->IsJSValue()) {
11331 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11332 if (script_object->IsJSValue()) {
11333 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011334 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011335 }
11336
11337 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11338 } else {
11339 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11340 // and we check it in this function.
11341 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011342
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011343 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011344}
11345
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011346
11347// In a code of a parent function replaces original function as embedded object
11348// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011349RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011350 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011351 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011352
11353 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11354 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11355 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11356
11357 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11358 subst_wrapper);
11359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011361}
11362
11363
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011364// Updates positions of a shared function info (first parameter) according
11365// to script source change. Text change is described in second parameter as
11366// array of groups of 3 numbers:
11367// (change_begin, change_end, change_end_new_position).
11368// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011369RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011370 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011372 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11373 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11374
ager@chromium.orgac091b72010-05-05 07:34:42 +000011375 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011376}
11377
11378
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011379// For array of SharedFunctionInfo's (each wrapped in JSValue)
11380// checks that none of them have activations on stacks (of any thread).
11381// Returns array of the same length with corresponding results of
11382// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011383RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011384 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011385 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011386 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011387 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011388
ager@chromium.org357bf652010-04-12 11:30:10 +000011389 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011390}
11391
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011392// Compares 2 strings line-by-line, then token-wise and returns diff in form
11393// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11394// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011395RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011396 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011397 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011398 CONVERT_ARG_CHECKED(String, s1, 0);
11399 CONVERT_ARG_CHECKED(String, s2, 1);
11400
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011401 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011402}
11403
11404
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011405// A testing entry. Returns statement position which is the closest to
11406// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011407RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011408 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011409 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011410 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11411 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011414
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011415 if (code->kind() != Code::FUNCTION &&
11416 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011418 }
11419
11420 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011421 int closest_pc = 0;
11422 int distance = kMaxInt;
11423 while (!it.done()) {
11424 int statement_position = static_cast<int>(it.rinfo()->data());
11425 // Check if this break point is closer that what was previously found.
11426 if (source_position <= statement_position &&
11427 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011428 closest_pc =
11429 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011430 distance = statement_position - source_position;
11431 // Check whether we can't get any closer.
11432 if (distance == 0) break;
11433 }
11434 it.next();
11435 }
11436
11437 return Smi::FromInt(closest_pc);
11438}
11439
11440
ager@chromium.org357bf652010-04-12 11:30:10 +000011441// Calls specified function with or without entering the debugger.
11442// This is used in unit tests to run code as if debugger is entered or simply
11443// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011444RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011445 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011446 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011447 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11448 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11449
11450 Handle<Object> result;
11451 bool pending_exception;
11452 {
11453 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011454 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011455 &pending_exception);
11456 } else {
11457 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011458 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011459 &pending_exception);
11460 }
11461 }
11462 if (!pending_exception) {
11463 return *result;
11464 } else {
11465 return Failure::Exception();
11466 }
11467}
11468
11469
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011470// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011471RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011472 CONVERT_CHECKED(String, arg, args[0]);
11473 SmartPointer<char> flags =
11474 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11475 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011476 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011477}
11478
11479
11480// Performs a GC.
11481// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011482RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 isolate->heap()->CollectAllGarbage(true);
11484 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011485}
11486
11487
11488// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011489RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011490 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011491 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011492 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011493 }
11494 return Smi::FromInt(usage);
11495}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011496
11497
11498// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011499RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011500#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011501 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011502#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011503 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011504#endif
11505}
11506
11507
11508// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011509RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011510#ifdef LIVE_OBJECT_LIST
11511 return LiveObjectList::Capture();
11512#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011513 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011514#endif
11515}
11516
11517
11518// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011519RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011520#ifdef LIVE_OBJECT_LIST
11521 CONVERT_SMI_CHECKED(id, args[0]);
11522 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011523 return success ? isolate->heap()->true_value() :
11524 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011525#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011527#endif
11528}
11529
11530
11531// Generates the response to a debugger request for a dump of the objects
11532// contained in the difference between the captured live object lists
11533// specified by id1 and id2.
11534// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11535// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011537#ifdef LIVE_OBJECT_LIST
11538 HandleScope scope;
11539 CONVERT_SMI_CHECKED(id1, args[0]);
11540 CONVERT_SMI_CHECKED(id2, args[1]);
11541 CONVERT_SMI_CHECKED(start, args[2]);
11542 CONVERT_SMI_CHECKED(count, args[3]);
11543 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11544 EnterDebugger enter_debugger;
11545 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11546#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011548#endif
11549}
11550
11551
11552// Gets the specified object as requested by the debugger.
11553// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011554RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011555#ifdef LIVE_OBJECT_LIST
11556 CONVERT_SMI_CHECKED(obj_id, args[0]);
11557 Object* result = LiveObjectList::GetObj(obj_id);
11558 return result;
11559#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011561#endif
11562}
11563
11564
11565// Gets the obj id for the specified address if valid.
11566// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011567RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011568#ifdef LIVE_OBJECT_LIST
11569 HandleScope scope;
11570 CONVERT_ARG_CHECKED(String, address, 0);
11571 Object* result = LiveObjectList::GetObjId(address);
11572 return result;
11573#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011575#endif
11576}
11577
11578
11579// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011580RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011581#ifdef LIVE_OBJECT_LIST
11582 HandleScope scope;
11583 CONVERT_SMI_CHECKED(obj_id, args[0]);
11584 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11585 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11586 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11587 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11588 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11589
11590 Handle<JSObject> instance_filter;
11591 if (args[1]->IsJSObject()) {
11592 instance_filter = args.at<JSObject>(1);
11593 }
11594 bool verbose = false;
11595 if (args[2]->IsBoolean()) {
11596 verbose = args[2]->IsTrue();
11597 }
11598 int start = 0;
11599 if (args[3]->IsSmi()) {
11600 start = Smi::cast(args[3])->value();
11601 }
11602 int limit = Smi::kMaxValue;
11603 if (args[4]->IsSmi()) {
11604 limit = Smi::cast(args[4])->value();
11605 }
11606
11607 return LiveObjectList::GetObjRetainers(obj_id,
11608 instance_filter,
11609 verbose,
11610 start,
11611 limit,
11612 filter_obj);
11613#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011615#endif
11616}
11617
11618
11619// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011620RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011621#ifdef LIVE_OBJECT_LIST
11622 HandleScope scope;
11623 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11624 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11625 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11626
11627 Handle<JSObject> instance_filter;
11628 if (args[2]->IsJSObject()) {
11629 instance_filter = args.at<JSObject>(2);
11630 }
11631
11632 Object* result =
11633 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11634 return result;
11635#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011637#endif
11638}
11639
11640
11641// Generates the response to a debugger request for a list of all
11642// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011643RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011644#ifdef LIVE_OBJECT_LIST
11645 CONVERT_SMI_CHECKED(start, args[0]);
11646 CONVERT_SMI_CHECKED(count, args[1]);
11647 return LiveObjectList::Info(start, count);
11648#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011650#endif
11651}
11652
11653
11654// Gets a dump of the specified object as requested by the debugger.
11655// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011656RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011657#ifdef LIVE_OBJECT_LIST
11658 HandleScope scope;
11659 CONVERT_SMI_CHECKED(obj_id, args[0]);
11660 Object* result = LiveObjectList::PrintObj(obj_id);
11661 return result;
11662#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011664#endif
11665}
11666
11667
11668// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011669RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011670#ifdef LIVE_OBJECT_LIST
11671 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011673#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011674 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011675#endif
11676}
11677
11678
11679// Generates the response to a debugger request for a summary of the types
11680// of objects in the difference between the captured live object lists
11681// specified by id1 and id2.
11682// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11683// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011684RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011685#ifdef LIVE_OBJECT_LIST
11686 HandleScope scope;
11687 CONVERT_SMI_CHECKED(id1, args[0]);
11688 CONVERT_SMI_CHECKED(id2, args[1]);
11689 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11690
11691 EnterDebugger enter_debugger;
11692 return LiveObjectList::Summarize(id1, id2, filter_obj);
11693#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011694 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011695#endif
11696}
11697
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011698#endif // ENABLE_DEBUGGER_SUPPORT
11699
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011700
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011701#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011702RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011703 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011704 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011705
11706 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011707 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11708 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011709 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011710}
11711
11712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011713RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011714 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011715 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011716
11717 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011718 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11719 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011721}
11722
11723#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011725// Finds the script object from the script data. NOTE: This operation uses
11726// heap traversal to find the function generated for the source position
11727// for the requested break point. For lazily compiled functions several heap
11728// traversals might be required rendering this operation as a rather slow
11729// operation. However for setting break points which is normally done through
11730// some kind of user interaction the performance is not crucial.
11731static Handle<Object> Runtime_GetScriptFromScriptName(
11732 Handle<String> script_name) {
11733 // Scan the heap for Script objects to find the script with the requested
11734 // script data.
11735 Handle<Script> script;
11736 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011737 HeapObject* obj = NULL;
11738 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011739 // If a script is found check if it has the script data requested.
11740 if (obj->IsScript()) {
11741 if (Script::cast(obj)->name()->IsString()) {
11742 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11743 script = Handle<Script>(Script::cast(obj));
11744 }
11745 }
11746 }
11747 }
11748
11749 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011750 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011751
11752 // Return the script found.
11753 return GetScriptWrapper(script);
11754}
11755
11756
11757// Get the script object from script data. NOTE: Regarding performance
11758// see the NOTE for GetScriptFromScriptData.
11759// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011760RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762
11763 ASSERT(args.length() == 1);
11764
11765 CONVERT_CHECKED(String, script_name, args[0]);
11766
11767 // Find the requested script.
11768 Handle<Object> result =
11769 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11770 return *result;
11771}
11772
11773
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011774// Determines whether the given stack frame should be displayed in
11775// a stack trace. The caller is the error constructor that asked
11776// for the stack trace to be collected. The first time a construct
11777// call to this function is encountered it is skipped. The seen_caller
11778// in/out parameter is used to remember if the caller has been seen
11779// yet.
11780static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11781 bool* seen_caller) {
11782 // Only display JS frames.
11783 if (!raw_frame->is_java_script())
11784 return false;
11785 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11786 Object* raw_fun = frame->function();
11787 // Not sure when this can happen but skip it just in case.
11788 if (!raw_fun->IsJSFunction())
11789 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011790 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011791 *seen_caller = true;
11792 return false;
11793 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011794 // Skip all frames until we've seen the caller. Also, skip the most
11795 // obvious builtin calls. Some builtin calls (such as Number.ADD
11796 // which is invoked using 'call') are very difficult to recognize
11797 // so we're leaving them in for now.
11798 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011799}
11800
11801
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011802// Collect the raw data for a stack trace. Returns an array of 4
11803// element segments each containing a receiver, function, code and
11804// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011805RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011806 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011807 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011808 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11809
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 HandleScope scope(isolate);
11811 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011812
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011813 limit = Max(limit, 0); // Ensure that limit is not negative.
11814 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011815 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011816 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011817
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011818 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011819 // If the caller parameter is a function we skip frames until we're
11820 // under it before starting to collect.
11821 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011822 int cursor = 0;
11823 int frames_seen = 0;
11824 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011825 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011826 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011827 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011828 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011829 // Set initial size to the maximum inlining level + 1 for the outermost
11830 // function.
11831 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011832 frame->Summarize(&frames);
11833 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011834 if (cursor + 4 > elements->length()) {
11835 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11836 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011837 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011838 for (int i = 0; i < cursor; i++) {
11839 new_elements->set(i, elements->get(i));
11840 }
11841 elements = new_elements;
11842 }
11843 ASSERT(cursor + 4 <= elements->length());
11844
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011845 Handle<Object> recv = frames[i].receiver();
11846 Handle<JSFunction> fun = frames[i].function();
11847 Handle<Code> code = frames[i].code();
11848 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011849 elements->set(cursor++, *recv);
11850 elements->set(cursor++, *fun);
11851 elements->set(cursor++, *code);
11852 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011853 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011854 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011855 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011856 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011857 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011858 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011859 return *result;
11860}
11861
11862
ager@chromium.org3811b432009-10-28 14:53:37 +000011863// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011864RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011865 ASSERT_EQ(args.length(), 0);
11866
11867 NoHandleAllocation ha;
11868
11869 const char* version_string = v8::V8::GetVersion();
11870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11872 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011873}
11874
11875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 ASSERT(args.length() == 2);
11878 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11879 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881 OS::Abort();
11882 UNREACHABLE();
11883 return NULL;
11884}
11885
11886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011887RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011888 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011889 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011890 Object* key = args[1];
11891
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011892 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011893 Object* o = cache->get(finger_index);
11894 if (o == key) {
11895 // The fastest case: hit the same place again.
11896 return cache->get(finger_index + 1);
11897 }
11898
11899 for (int i = finger_index - 2;
11900 i >= JSFunctionResultCache::kEntriesIndex;
11901 i -= 2) {
11902 o = cache->get(i);
11903 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011904 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011905 return cache->get(i + 1);
11906 }
11907 }
11908
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011909 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011910 ASSERT(size <= cache->length());
11911
11912 for (int i = size - 2; i > finger_index; i -= 2) {
11913 o = cache->get(i);
11914 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011915 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011916 return cache->get(i + 1);
11917 }
11918 }
11919
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011920 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011922
11923 Handle<JSFunctionResultCache> cache_handle(cache);
11924 Handle<Object> key_handle(key);
11925 Handle<Object> value;
11926 {
11927 Handle<JSFunction> factory(JSFunction::cast(
11928 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11929 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011930 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011931 // This handle is nor shared, nor used later, so it's safe.
11932 Object** argv[] = { key_handle.location() };
11933 bool pending_exception = false;
11934 value = Execution::Call(factory,
11935 receiver,
11936 1,
11937 argv,
11938 &pending_exception);
11939 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011940 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011941
11942#ifdef DEBUG
11943 cache_handle->JSFunctionResultCacheVerify();
11944#endif
11945
11946 // Function invocation may have cleared the cache. Reread all the data.
11947 finger_index = cache_handle->finger_index();
11948 size = cache_handle->size();
11949
11950 // If we have spare room, put new data into it, otherwise evict post finger
11951 // entry which is likely to be the least recently used.
11952 int index = -1;
11953 if (size < cache_handle->length()) {
11954 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11955 index = size;
11956 } else {
11957 index = finger_index + JSFunctionResultCache::kEntrySize;
11958 if (index == cache_handle->length()) {
11959 index = JSFunctionResultCache::kEntriesIndex;
11960 }
11961 }
11962
11963 ASSERT(index % 2 == 0);
11964 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11965 ASSERT(index < cache_handle->length());
11966
11967 cache_handle->set(index, *key_handle);
11968 cache_handle->set(index + 1, *value);
11969 cache_handle->set_finger_index(index);
11970
11971#ifdef DEBUG
11972 cache_handle->JSFunctionResultCacheVerify();
11973#endif
11974
11975 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011976}
11977
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011979RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011980 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011981 CONVERT_ARG_CHECKED(String, type, 0);
11982 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983 return *isolate->factory()->NewJSMessageObject(
11984 type,
11985 arguments,
11986 0,
11987 0,
11988 isolate->factory()->undefined_value(),
11989 isolate->factory()->undefined_value(),
11990 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011991}
11992
11993
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011994RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011995 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11996 return message->type();
11997}
11998
11999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012000RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012001 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12002 return message->arguments();
12003}
12004
12005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012006RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012007 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12008 return Smi::FromInt(message->start_position());
12009}
12010
12011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012012RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012013 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12014 return message->script();
12015}
12016
12017
kasper.lund44510672008-07-25 07:37:58 +000012018#ifdef DEBUG
12019// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12020// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012021RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012022 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012023 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012024#define COUNT_ENTRY(Name, argc, ressize) + 1
12025 int entry_count = 0
12026 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12027 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12028 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12029#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 Factory* factory = isolate->factory();
12031 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012033 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012034#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012035 { \
12036 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012037 Handle<String> name; \
12038 /* Inline runtime functions have an underscore in front of the name. */ \
12039 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012040 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012041 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12042 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012044 Vector<const char>(#Name, StrLength(#Name))); \
12045 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012046 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012047 pair_elements->set(0, *name); \
12048 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012049 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012050 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012052 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012054 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012055 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012056 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012057#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012058 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012059 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012060 return *result;
12061}
kasper.lund44510672008-07-25 07:37:58 +000012062#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063
12064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012065RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012066 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012067 CONVERT_CHECKED(String, format, args[0]);
12068 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012069 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012070 LOGGER->LogRuntime(chars, elms);
12071 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012072}
12073
12074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012075RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 UNREACHABLE(); // implemented as macro in the parser
12077 return NULL;
12078}
12079
12080
12081// ----------------------------------------------------------------------------
12082// Implementation of Runtime
12083
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012084#define F(name, number_of_args, result_size) \
12085 { Runtime::k##name, Runtime::RUNTIME, #name, \
12086 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012088
12089#define I(name, number_of_args, result_size) \
12090 { Runtime::kInline##name, Runtime::INLINE, \
12091 "_" #name, NULL, number_of_args, result_size },
12092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012095 INLINE_FUNCTION_LIST(I)
12096 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097};
12098
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012100MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12101 Object* dictionary) {
12102 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012103 ASSERT(dictionary != NULL);
12104 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12105 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012106 Object* name_symbol;
12107 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012108 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012109 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12110 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012111 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012112 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12113 String::cast(name_symbol),
12114 Smi::FromInt(i),
12115 PropertyDetails(NONE, NORMAL));
12116 if (!maybe_dictionary->ToObject(&dictionary)) {
12117 // Non-recoverable failure. Calling code must restart heap
12118 // initialization.
12119 return maybe_dictionary;
12120 }
12121 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012122 }
12123 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124}
12125
12126
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012127const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12128 Heap* heap = name->GetHeap();
12129 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012130 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012132 int function_index = Smi::cast(smi_index)->value();
12133 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 }
12135 return NULL;
12136}
12137
12138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012139const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012140 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12141}
12142
12143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012145 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012146 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012147 if (failure->IsRetryAfterGC()) {
12148 // Try to do a garbage collection; ignore it if it fails. The C
12149 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012150 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012151 } else {
12152 // Handle last resort GC and make sure to allow future allocations
12153 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012154 isolate->counters()->gc_last_resort_from_js()->Increment();
12155 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012156 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157}
12158
12159
12160} } // namespace v8::internal