blob: c7ff3a392b27748ddf4ae9231f24ff76ea33fed0 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 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"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.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"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 }
128 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000138 }
139 }
140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000141 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000174 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000222 }
223 return copy;
224}
225
226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230}
231
232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236}
237
238
ager@chromium.org236ad962008-09-25 09:45:57 +0000239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000290}
291
292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298
299static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 bool should_have_fast_elements,
304 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000400 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401}
402
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000498 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000505
506 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 should_have_fast_elements,
513 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519}
520
521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000524 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531
532 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000537 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 should_have_fast_elements,
539 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000582 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000584 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587}
588
589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 isolate->context()->global_context()->
597 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
ager@chromium.org32912102009-01-16 10:38:43 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000604 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
ager@chromium.org32912102009-01-16 10:38:43 +0000610 return object;
611}
612
613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 return JSObject::cast(obj)->class_name();
620}
621
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 V = prototype;
634 }
635}
636
637
ager@chromium.org9085a012009-05-11 19:22:57 +0000638// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
lrn@chromium.org303ada72010-10-27 09:33:13 +0000661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000678}
679
680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000683 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000684 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 return false;
784 }
785
786 return true;
787}
788
789
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000846 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000879 break;
880 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000882 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000885 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000886 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000890 default:
891 UNREACHABLE();
892 break;
893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 return *desc;
897 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000898 }
899 }
900
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000907
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910 }
911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000932
933 PropertyAttributes attrs;
934 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 return *desc;
943}
944
945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000964}
965
966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
ager@chromium.org32912102009-01-16 10:38:43 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
ager@chromium.org32912102009-01-16 10:38:43 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049}
1050
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070
ager@chromium.org3811b432009-10-28 14:53:37 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 }
1133 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
1187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 name,
1191 value,
1192 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
ager@chromium.org7c537e22008-10-16 08:43:32 +00001212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001225 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001255 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001260 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 }
1265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001272 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 }
1304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001307 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 }
1309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 if (assign) {
1403 return global->SetProperty(*name, args[2], attributes, strict_mode);
1404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001429 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001460 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 ASSERT(args.length() == 3);
1502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001514 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 context->Lookup(name, flags, &index, &attributes);
1516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001543 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001545 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 }
1547 return *value;
1548 }
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001558 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001559 return *value;
1560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001596 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001621 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001624 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001625 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001626 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001628 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001634 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001636 if (result.is_null()) return Failure::Exception();
1637 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001646 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001652 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001657 {
1658 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 }
1663 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001682
1683 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001685
1686 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001714 source,
1715 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001716 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001718 global,
1719 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 ASSERT(!result->IsFailure());
1721 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001723 ignoreCase,
1724 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 multiline,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
1730 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 Smi::FromInt(0),
1733 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001736 return regexp;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001747 return Smi::FromInt(0);
1748}
1749
1750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001754 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 return optimized;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
1782 return *holder;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001787 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 Context* global_context =
1789 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 return global_context->global()->global_receiver();
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->GetSourceCode();
1874}
1875
1876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001888 ASSERT(args.length() == 2);
1889
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001927 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return args[0]; // return TOS
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001944}
1945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001954}
1955
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 ASSERT(args.length() == 2);
1960
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return Failure::Exception();
1973 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001980 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001982 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001991 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002028}
2029
2030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002033 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002035 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002037 }
2038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002049 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002060 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076}
2077
2078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083}
2084
lrn@chromium.org25156de2010-04-06 13:10:27 +00002085
2086class FixedArrayBuilder {
2087 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002167// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185class ReplacementStringBuilder {
2186 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002194 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002212 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002234 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 *array_builder_.array(),
2255 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 *array_builder_.array(),
2265 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002272 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002303 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002466 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002497 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002504 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002513 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002603 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002634 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002684template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002686 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002690 ASSERT(subject->IsFlat());
2691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
2716 int length = subject->length();
2717 int new_length = length - (end - start);
2718 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808
2809 return *answer;
2810}
2811
2812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850 }
2851 }
2852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
ager@chromium.org7c537e22008-10-16 08:43:32 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002870
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002871 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002872 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002874 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875 if (start_index + pattern_length > subject_length) return -1;
2876
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002879
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002884 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002900 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002917 ASSERT(args.length() == 3);
2918
ager@chromium.org7c537e22008-10-16 08:43:32 +00002919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 Object* index = args[2];
2923 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925
ager@chromium.org870a0b62008-11-04 11:43:05 +00002926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930}
2931
2932
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002933template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002936 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 break;
2957 }
2958 j++;
2959 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002969 ASSERT(args.length() == 3);
2970
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002980
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 int str1_length = str1->length();
3033 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003048 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 if (d != 0) return Smi::FromInt(d);
3050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003051 str1->TryFlatten();
3052 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003093 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003095 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096}
3097
3098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003113 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 }
3115 int length = subject->length();
3116
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003171template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003197 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003201 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003203 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 builder,
3237 &match_pos)) break;
3238 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003252 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 builder,
3254 &match_pos)) break;
3255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003259 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003418 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003489 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 return *builder.ToJSArray(result_array);
3493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003534 }
3535 }
3536
3537 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581}
3582
3583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003638 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003639 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003640 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 return prototype->GetElement(index);
3666 }
3667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 return GetElement(object, index);
3669}
3670
3671
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 return object->GetElement(index);
3674}
3675
3676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 bool has_pending_exception = false;
3702 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
ager@chromium.org32912102009-01-16 10:38:43 +00003708 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716}
3717
3718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727}
3728
3729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003739 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003757 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003764 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003767 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 }
3769 } else {
3770 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003775 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792
3793 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003796 args.at<Object>(1));
3797}
3798
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
3824 if (result.IsProperty() &&
3825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003865 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003874 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003879 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003881 }
3882
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003884 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003885
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003902 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003907 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
3923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003926 Handle<Object> key,
3927 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003929 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003933 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 // Check if the given key is an array index.
3946 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003947 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return *value;
3962 }
3963
3964 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003970 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 }
3988}
3989
3990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004000 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004017 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004020 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038}
4039
4040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004048 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004073 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004092 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return Runtime::SetObjectProperty(isolate,
4101 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004127 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004134 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004138 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004139 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004147 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
ager@chromium.org9085a012009-05-11 19:22:57 +00004168 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004184 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004185 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 }
4233
ager@chromium.org870a0b62008-11-04 11:43:05 +00004234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236}
4237
4238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004242 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
4299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 }
4307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004314 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
4318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 }
4326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
4342 for (int i = 0; i < length; i++) {
4343 jsproto->GetLocalPropertyNames(*names,
4344 i == 0 ? 0 : local_property_count[i - 1]);
4345 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4346 proto_with_hidden_properties++;
4347 }
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Filter out name of hidden propeties object.
4354 if (proto_with_hidden_properties > 0) {
4355 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 names->length() - proto_with_hidden_properties);
4358 int dest_pos = 0;
4359 for (int i = 0; i < total_property_count; i++) {
4360 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 continue;
4363 }
4364 names->set(dest_pos++, name);
4365 }
4366 }
4367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369}
4370
4371
4372// Return the names of the local indexed properties.
4373// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 ASSERT(args.length() == 1);
4377 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 }
4380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4381
4382 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004383 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386}
4387
4388
4389// Return information on whether an object has a named or indexed interceptor.
4390// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 ASSERT(args.length() == 1);
4394 if (!args[0]->IsJSObject()) {
4395 return Smi::FromInt(0);
4396 }
4397 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4398
4399 int result = 0;
4400 if (obj->HasNamedInterceptor()) result |= 2;
4401 if (obj->HasIndexedInterceptor()) result |= 1;
4402
4403 return Smi::FromInt(result);
4404}
4405
4406
4407// Return property names from named interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4413
4414 if (obj->HasNamedInterceptor()) {
4415 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4416 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419}
4420
4421
4422// Return element names from indexed interceptor.
4423// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004424RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004426 ASSERT(args.length() == 1);
4427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4428
4429 if (obj->HasIndexedInterceptor()) {
4430 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4431 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004438 ASSERT_EQ(args.length(), 1);
4439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004441 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004442
4443 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004444 // Do access checks before going to the global object.
4445 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004447 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4449 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004450 }
4451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004452 Handle<Object> proto(object->GetPrototype());
4453 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004455 object = Handle<JSObject>::cast(proto);
4456 }
4457
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004458 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4459 LOCAL_ONLY);
4460 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4461 // property array and since the result is mutable we have to create
4462 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004463 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004465 for (int i = 0; i < length; i++) {
4466 Object* entry = contents->get(i);
4467 if (entry->IsString()) {
4468 copy->set(i, entry);
4469 } else {
4470 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 HandleScope scope(isolate);
4472 Handle<Object> entry_handle(entry, isolate);
4473 Handle<Object> entry_str =
4474 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004475 copy->set(i, *entry_str);
4476 }
4477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479}
4480
4481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004482RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 NoHandleAllocation ha;
4484 ASSERT(args.length() == 1);
4485
4486 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004487 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 it.AdvanceToArgumentsFrame();
4489 JavaScriptFrame* frame = it.frame();
4490
4491 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004492 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493
4494 // Try to convert the key to an index. If successful and within
4495 // index return the the argument from the frame.
4496 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004497 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 return frame->GetParameter(index);
4499 }
4500
4501 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool exception = false;
4504 Handle<Object> converted =
4505 Execution::ToString(args.at<Object>(0), &exception);
4506 if (exception) return Failure::Exception();
4507 Handle<String> key = Handle<String>::cast(converted);
4508
4509 // Try to convert the string key into an array index.
4510 if (key->AsArrayIndex(&index)) {
4511 if (index < n) {
4512 return frame->GetParameter(index);
4513 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 }
4516 }
4517
4518 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4520 if (key->Equals(isolate->heap()->callee_symbol())) {
4521 Object* function = frame->function();
4522 if (function->IsJSFunction() &&
4523 JSFunction::cast(function)->shared()->strict_mode()) {
4524 return isolate->Throw(*isolate->factory()->NewTypeError(
4525 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4526 }
4527 return function;
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004537
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004538 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004539 Handle<Object> object = args.at<Object>(0);
4540 if (object->IsJSObject()) {
4541 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004542 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 MaybeObject* ok = js_object->TransformToFastProperties(0);
4544 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004545 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004546 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004547 return *object;
4548}
4549
4550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004551RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004553
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004554 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004555 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004556 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004559 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004560 return *object;
4561}
4562
4563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 NoHandleAllocation ha;
4566 ASSERT(args.length() == 1);
4567
4568 return args[0]->ToBoolean();
4569}
4570
4571
4572// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4573// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
4576
4577 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 HeapObject* heap_obj = HeapObject::cast(obj);
4580
4581 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 if (heap_obj->map()->is_undetectable()) {
4583 return isolate->heap()->undefined_symbol();
4584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585
4586 InstanceType instance_type = heap_obj->map()->instance_type();
4587 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590
4591 switch (instance_type) {
4592 case ODDBALL_TYPE:
4593 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 }
4596 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004601 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 default:
4604 // For any kind of object not handled above, the spec rule for
4605 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608}
4609
4610
lrn@chromium.org25156de2010-04-06 13:10:27 +00004611static bool AreDigits(const char*s, int from, int to) {
4612 for (int i = from; i < to; i++) {
4613 if (s[i] < '0' || s[i] > '9') return false;
4614 }
4615
4616 return true;
4617}
4618
4619
4620static int ParseDecimalInteger(const char*s, int from, int to) {
4621 ASSERT(to - from < 10); // Overflow is not possible.
4622 ASSERT(from < to);
4623 int d = s[from] - '0';
4624
4625 for (int i = from + 1; i < to; i++) {
4626 d = 10 * d + (s[i] - '0');
4627 }
4628
4629 return d;
4630}
4631
4632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 NoHandleAllocation ha;
4635 ASSERT(args.length() == 1);
4636 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004638
4639 // Fast case: short integer or some sorts of junk values.
4640 int len = subject->length();
4641 if (subject->IsSeqAsciiString()) {
4642 if (len == 0) return Smi::FromInt(0);
4643
4644 char const* data = SeqAsciiString::cast(subject)->GetChars();
4645 bool minus = (data[0] == '-');
4646 int start_pos = (minus ? 1 : 0);
4647
4648 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650 } else if (data[start_pos] > '9') {
4651 // Fast check for a junk value. A valid string may start from a
4652 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4653 // the 'I' character ('Infinity'). All of that have codes not greater than
4654 // '9' except 'I'.
4655 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004657 }
4658 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4659 // The maximal/minimal smi has 10 digits. If the string has less digits we
4660 // know it will fit into the smi-data type.
4661 int d = ParseDecimalInteger(data, start_pos, len);
4662 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004664 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004665 } else if (!subject->HasHashCode() &&
4666 len <= String::kMaxArrayIndexSize &&
4667 (len == 1 || data[0] != '0')) {
4668 // String hash is not calculated yet but all the data are present.
4669 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004670 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004671#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672 subject->Hash(); // Force hash calculation.
4673 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4674 static_cast<int>(hash));
4675#endif
4676 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677 }
4678 return Smi::FromInt(d);
4679 }
4680 }
4681
4682 // Slower case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 return isolate->heap()->NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684}
4685
4686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation ha;
4689 ASSERT(args.length() == 1);
4690
4691 CONVERT_CHECKED(JSArray, codes, args[0]);
4692 int length = Smi::cast(codes->length())->value();
4693
4694 // Check if the string can be ASCII.
4695 int i;
4696 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004697 Object* element;
4698 { MaybeObject* maybe_element = codes->GetElement(i);
4699 // We probably can't get an exception here, but just in order to enforce
4700 // the checking of inputs in the runtime calls we check here.
4701 if (!maybe_element->ToObject(&element)) return maybe_element;
4702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4704 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4705 break;
4706 }
4707
lrn@chromium.org303ada72010-10-27 09:33:13 +00004708 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 }
4714
lrn@chromium.org303ada72010-10-27 09:33:13 +00004715 Object* object = NULL;
4716 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717 String* result = String::cast(object);
4718 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004719 Object* element;
4720 { MaybeObject* maybe_element = codes->GetElement(i);
4721 if (!maybe_element->ToObject(&element)) return maybe_element;
4722 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004724 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 }
4726 return result;
4727}
4728
4729
4730// kNotEscaped is generated by the following:
4731//
4732// #!/bin/perl
4733// for (my $i = 0; $i < 256; $i++) {
4734// print "\n" if $i % 16 == 0;
4735// my $c = chr($i);
4736// my $escaped = 1;
4737// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4738// print $escaped ? "0, " : "1, ";
4739// }
4740
4741
4742static bool IsNotEscaped(uint16_t character) {
4743 // Only for 8 bit characters, the rest are always escaped (in a different way)
4744 ASSERT(character < 256);
4745 static const char kNotEscaped[256] = {
4746 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4749 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4752 0, 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, 0,
4754 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 };
4763 return kNotEscaped[character] != 0;
4764}
4765
4766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004767RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004768 const char hex_chars[] = "0123456789ABCDEF";
4769 NoHandleAllocation ha;
4770 ASSERT(args.length() == 1);
4771 CONVERT_CHECKED(String, source, args[0]);
4772
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004773 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774
4775 int escaped_length = 0;
4776 int length = source->length();
4777 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 Access<StringInputBuffer> buffer(
4779 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 buffer->Reset(source);
4781 while (buffer->has_more()) {
4782 uint16_t character = buffer->GetNext();
4783 if (character >= 256) {
4784 escaped_length += 6;
4785 } else if (IsNotEscaped(character)) {
4786 escaped_length++;
4787 } else {
4788 escaped_length += 3;
4789 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004790 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004791 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004792 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 return Failure::OutOfMemoryException();
4795 }
4796 }
4797 }
4798 // No length change implies no change. Return original string if no change.
4799 if (escaped_length == length) {
4800 return source;
4801 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004802 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004803 { MaybeObject* maybe_o =
4804 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805 if (!maybe_o->ToObject(&o)) return maybe_o;
4806 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 String* destination = String::cast(o);
4808 int dest_position = 0;
4809
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004810 Access<StringInputBuffer> buffer(
4811 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 buffer->Rewind();
4813 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004814 uint16_t chr = buffer->GetNext();
4815 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004816 destination->Set(dest_position, '%');
4817 destination->Set(dest_position+1, 'u');
4818 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4819 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4820 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4821 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004823 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004824 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 dest_position++;
4826 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004827 destination->Set(dest_position, '%');
4828 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4829 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 dest_position += 3;
4831 }
4832 }
4833 return destination;
4834}
4835
4836
4837static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4838 static const signed char kHexValue['g'] = {
4839 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4840 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4843 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4844 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4845 -1, 10, 11, 12, 13, 14, 15 };
4846
4847 if (character1 > 'f') return -1;
4848 int hi = kHexValue[character1];
4849 if (hi == -1) return -1;
4850 if (character2 > 'f') return -1;
4851 int lo = kHexValue[character2];
4852 if (lo == -1) return -1;
4853 return (hi << 4) + lo;
4854}
4855
4856
ager@chromium.org870a0b62008-11-04 11:43:05 +00004857static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004858 int i,
4859 int length,
4860 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004861 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004862 int32_t hi = 0;
4863 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 if (character == '%' &&
4865 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004866 source->Get(i + 1) == 'u' &&
4867 (hi = TwoDigitHex(source->Get(i + 2),
4868 source->Get(i + 3))) != -1 &&
4869 (lo = TwoDigitHex(source->Get(i + 4),
4870 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004871 *step = 6;
4872 return (hi << 8) + lo;
4873 } else if (character == '%' &&
4874 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004875 (lo = TwoDigitHex(source->Get(i + 1),
4876 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 *step = 3;
4878 return lo;
4879 } else {
4880 *step = 1;
4881 return character;
4882 }
4883}
4884
4885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004886RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887 NoHandleAllocation ha;
4888 ASSERT(args.length() == 1);
4889 CONVERT_CHECKED(String, source, args[0]);
4890
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004891 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892
4893 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004894 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895
4896 int unescaped_length = 0;
4897 for (int i = 0; i < length; unescaped_length++) {
4898 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004899 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004901 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 i += step;
4903 }
4904
4905 // No length change implies no change. Return original string if no change.
4906 if (unescaped_length == length)
4907 return source;
4908
lrn@chromium.org303ada72010-10-27 09:33:13 +00004909 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004910 { MaybeObject* maybe_o =
4911 ascii ?
4912 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4913 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004914 if (!maybe_o->ToObject(&o)) return maybe_o;
4915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 String* destination = String::cast(o);
4917
4918 int dest_position = 0;
4919 for (int i = 0; i < length; dest_position++) {
4920 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004921 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922 i += step;
4923 }
4924 return destination;
4925}
4926
4927
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004928static const unsigned int kQuoteTableLength = 128u;
4929
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004930static const int kJsonQuotesCharactersPerEntry = 8;
4931static const char* const JsonQuotes =
4932 "\\u0000 \\u0001 \\u0002 \\u0003 "
4933 "\\u0004 \\u0005 \\u0006 \\u0007 "
4934 "\\b \\t \\n \\u000b "
4935 "\\f \\r \\u000e \\u000f "
4936 "\\u0010 \\u0011 \\u0012 \\u0013 "
4937 "\\u0014 \\u0015 \\u0016 \\u0017 "
4938 "\\u0018 \\u0019 \\u001a \\u001b "
4939 "\\u001c \\u001d \\u001e \\u001f "
4940 " ! \\\" # "
4941 "$ % & ' "
4942 "( ) * + "
4943 ", - . / "
4944 "0 1 2 3 "
4945 "4 5 6 7 "
4946 "8 9 : ; "
4947 "< = > ? "
4948 "@ A B C "
4949 "D E F G "
4950 "H I J K "
4951 "L M N O "
4952 "P Q R S "
4953 "T U V W "
4954 "X Y Z [ "
4955 "\\\\ ] ^ _ "
4956 "` a b c "
4957 "d e f g "
4958 "h i j k "
4959 "l m n o "
4960 "p q r s "
4961 "t u v w "
4962 "x y z { "
4963 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004964
4965
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004966// For a string that is less than 32k characters it should always be
4967// possible to allocate it in new space.
4968static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4969
4970
4971// Doing JSON quoting cannot make the string more than this many times larger.
4972static const int kJsonQuoteWorstCaseBlowup = 6;
4973
4974
4975// Covers the entire ASCII range (all other characters are unchanged by JSON
4976// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004977static const byte JsonQuoteLengths[kQuoteTableLength] = {
4978 6, 6, 6, 6, 6, 6, 6, 6,
4979 2, 2, 2, 6, 2, 2, 6, 6,
4980 6, 6, 6, 6, 6, 6, 6, 6,
4981 6, 6, 6, 6, 6, 6, 6, 6,
4982 1, 1, 2, 1, 1, 1, 1, 1,
4983 1, 1, 1, 1, 1, 1, 1, 1,
4984 1, 1, 1, 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, 2, 1, 1, 1,
4990 1, 1, 1, 1, 1, 1, 1, 1,
4991 1, 1, 1, 1, 1, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994};
4995
4996
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004997template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004999
5000
5001template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005002MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5003 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005004}
5005
5006
5007template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005008MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5009 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005010}
5011
5012
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005013template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5015 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005016 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005017 const Char* read_cursor = characters.start();
5018 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005019 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005020 int quoted_length = kSpaceForQuotes;
5021 while (read_cursor < end) {
5022 Char c = *(read_cursor++);
5023 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5024 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005025 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005026 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027 }
5028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005029 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5030 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005031 Object* new_object;
5032 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005033 return new_alloc;
5034 }
5035 StringType* new_string = StringType::cast(new_object);
5036
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005037 Char* write_cursor = reinterpret_cast<Char*>(
5038 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005039 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005040 *(write_cursor++) = '"';
5041
5042 read_cursor = characters.start();
5043 while (read_cursor < end) {
5044 Char c = *(read_cursor++);
5045 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5046 *(write_cursor++) = c;
5047 } else {
5048 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5049 const char* replacement = JsonQuotes +
5050 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5051 for (int i = 0; i < len; i++) {
5052 *write_cursor++ = *replacement++;
5053 }
5054 }
5055 }
5056 *(write_cursor++) = '"';
5057 return new_string;
5058}
5059
5060
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005061template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062static MaybeObject* QuoteJsonString(Isolate* isolate,
5063 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005064 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005066 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005067 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5068 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005069 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005070 }
5071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5073 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005074 Object* new_object;
5075 if (!new_alloc->ToObject(&new_object)) {
5076 return new_alloc;
5077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005079 // Even if our string is small enough to fit in new space we still have to
5080 // handle it being allocated in old space as may happen in the third
5081 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5082 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005083 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005084 }
5085 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005086 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005087
5088 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5089 Char* write_cursor = reinterpret_cast<Char*>(
5090 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005091 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005092 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005093
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005094 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005095 const Char* end = read_cursor + length;
5096 while (read_cursor < end) {
5097 Char c = *(read_cursor++);
5098 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5099 *(write_cursor++) = c;
5100 } else {
5101 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5102 const char* replacement = JsonQuotes +
5103 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5104 write_cursor[0] = replacement[0];
5105 if (len > 1) {
5106 write_cursor[1] = replacement[1];
5107 if (len > 2) {
5108 ASSERT(len == 6);
5109 write_cursor[2] = replacement[2];
5110 write_cursor[3] = replacement[3];
5111 write_cursor[4] = replacement[4];
5112 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005113 }
5114 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005115 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005116 }
5117 }
5118 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005119
5120 int final_length = static_cast<int>(
5121 write_cursor - reinterpret_cast<Char*>(
5122 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005123 isolate->heap()->new_space()->
5124 template ShrinkStringAtAllocationBoundary<StringType>(
5125 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126 return new_string;
5127}
5128
5129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005130RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005131 NoHandleAllocation ha;
5132 CONVERT_CHECKED(String, str, args[0]);
5133 if (!str->IsFlat()) {
5134 MaybeObject* try_flatten = str->TryFlatten();
5135 Object* flat;
5136 if (!try_flatten->ToObject(&flat)) {
5137 return try_flatten;
5138 }
5139 str = String::cast(flat);
5140 ASSERT(str->IsFlat());
5141 }
5142 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005143 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5144 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005145 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005146 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5147 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005148 }
5149}
5150
5151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005152RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005153 NoHandleAllocation ha;
5154 CONVERT_CHECKED(String, str, args[0]);
5155 if (!str->IsFlat()) {
5156 MaybeObject* try_flatten = str->TryFlatten();
5157 Object* flat;
5158 if (!try_flatten->ToObject(&flat)) {
5159 return try_flatten;
5160 }
5161 str = String::cast(flat);
5162 ASSERT(str->IsFlat());
5163 }
5164 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5166 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005167 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005168 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5169 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005170 }
5171}
5172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005173RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174 NoHandleAllocation ha;
5175
5176 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005177 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005179 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180
lrn@chromium.org25156de2010-04-06 13:10:27 +00005181 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5182 double value = StringToInt(s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005183 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184}
5185
5186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005187RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 NoHandleAllocation ha;
5189 CONVERT_CHECKED(String, str, args[0]);
5190
5191 // ECMA-262 section 15.1.2.3, empty string is NaN
5192 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5193
5194 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196}
5197
5198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005200MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202 String* s,
5203 int length,
5204 int input_string_length,
5205 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005206 // We try this twice, once with the assumption that the result is no longer
5207 // than the input and, if that assumption breaks, again with the exact
5208 // length. This may not be pretty, but it is nicer than what was here before
5209 // and I hereby claim my vaffel-is.
5210 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 // Allocate the resulting string.
5212 //
5213 // NOTE: This assumes that the upper/lower case of an ascii
5214 // character is also ascii. This is currently the case, but it
5215 // might break in the future if we implement more context and locale
5216 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005217 Object* o;
5218 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 ? isolate->heap()->AllocateRawAsciiString(length)
5220 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221 if (!maybe_o->ToObject(&o)) return maybe_o;
5222 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 String* result = String::cast(o);
5224 bool has_changed_character = false;
5225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 // Convert all characters to upper case, assuming that they will fit
5227 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005228 Access<StringInputBuffer> buffer(
5229 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005231 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 // We can assume that the string is not empty
5233 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005234 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005235 bool has_next = buffer->has_more();
5236 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 int char_length = mapping->get(current, next, chars);
5238 if (char_length == 0) {
5239 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005240 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 i++;
5242 } else if (char_length == 1) {
5243 // Common case: converting the letter resulted in one character.
5244 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005245 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 has_changed_character = true;
5247 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005248 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249 // We've assumed that the result would be as long as the
5250 // input but here is a character that converts to several
5251 // characters. No matter, we calculate the exact length
5252 // of the result and try the whole thing again.
5253 //
5254 // Note that this leaves room for optimization. We could just
5255 // memcpy what we already have to the result string. Also,
5256 // the result string is the last object allocated we could
5257 // "realloc" it and probably, in the vast majority of cases,
5258 // extend the existing string to be able to hold the full
5259 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005260 int next_length = 0;
5261 if (has_next) {
5262 next_length = mapping->get(next, 0, chars);
5263 if (next_length == 0) next_length = 1;
5264 }
5265 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 while (buffer->has_more()) {
5267 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005268 // NOTE: we use 0 as the next character here because, while
5269 // the next character may affect what a character converts to,
5270 // it does not in any case affect the length of what it convert
5271 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005272 int char_length = mapping->get(current, 0, chars);
5273 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005274 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005275 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005276 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 return Failure::OutOfMemoryException();
5278 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005279 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005280 // Try again with the real length.
5281 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 } else {
5283 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005284 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 i++;
5286 }
5287 has_changed_character = true;
5288 }
5289 current = next;
5290 }
5291 if (has_changed_character) {
5292 return result;
5293 } else {
5294 // If we didn't actually change anything in doing the conversion
5295 // we simple return the result and let the converted string
5296 // become garbage; there is no reason to keep two identical strings
5297 // alive.
5298 return s;
5299 }
5300}
5301
5302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005303namespace {
5304
lrn@chromium.org303ada72010-10-27 09:33:13 +00005305static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5306
5307
5308// Given a word and two range boundaries returns a word with high bit
5309// set in every byte iff the corresponding input byte was strictly in
5310// the range (m, n). All the other bits in the result are cleared.
5311// This function is only useful when it can be inlined and the
5312// boundaries are statically known.
5313// Requires: all bytes in the input word and the boundaries must be
5314// ascii (less than 0x7F).
5315static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5316 // Every byte in an ascii string is less than or equal to 0x7F.
5317 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5318 // Use strict inequalities since in edge cases the function could be
5319 // further simplified.
5320 ASSERT(0 < m && m < n && n < 0x7F);
5321 // Has high bit set in every w byte less than n.
5322 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5323 // Has high bit set in every w byte greater than m.
5324 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5325 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5326}
5327
5328
5329enum AsciiCaseConversion {
5330 ASCII_TO_LOWER,
5331 ASCII_TO_UPPER
5332};
5333
5334
5335template <AsciiCaseConversion dir>
5336struct FastAsciiConverter {
5337 static bool Convert(char* dst, char* src, int length) {
5338#ifdef DEBUG
5339 char* saved_dst = dst;
5340 char* saved_src = src;
5341#endif
5342 // We rely on the distance between upper and lower case letters
5343 // being a known power of 2.
5344 ASSERT('a' - 'A' == (1 << 5));
5345 // Boundaries for the range of input characters than require conversion.
5346 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5347 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5348 bool changed = false;
5349 char* const limit = src + length;
5350#ifdef V8_HOST_CAN_READ_UNALIGNED
5351 // Process the prefix of the input that requires no conversion one
5352 // (machine) word at a time.
5353 while (src <= limit - sizeof(uintptr_t)) {
5354 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5355 if (AsciiRangeMask(w, lo, hi) != 0) {
5356 changed = true;
5357 break;
5358 }
5359 *reinterpret_cast<uintptr_t*>(dst) = w;
5360 src += sizeof(uintptr_t);
5361 dst += sizeof(uintptr_t);
5362 }
5363 // Process the remainder of the input performing conversion when
5364 // required one word at a time.
5365 while (src <= limit - sizeof(uintptr_t)) {
5366 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5367 uintptr_t m = AsciiRangeMask(w, lo, hi);
5368 // The mask has high (7th) bit set in every byte that needs
5369 // conversion and we know that the distance between cases is
5370 // 1 << 5.
5371 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5372 src += sizeof(uintptr_t);
5373 dst += sizeof(uintptr_t);
5374 }
5375#endif
5376 // Process the last few bytes of the input (or the whole input if
5377 // unaligned access is not supported).
5378 while (src < limit) {
5379 char c = *src;
5380 if (lo < c && c < hi) {
5381 c ^= (1 << 5);
5382 changed = true;
5383 }
5384 *dst = c;
5385 ++src;
5386 ++dst;
5387 }
5388#ifdef DEBUG
5389 CheckConvert(saved_dst, saved_src, length, changed);
5390#endif
5391 return changed;
5392 }
5393
5394#ifdef DEBUG
5395 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5396 bool expected_changed = false;
5397 for (int i = 0; i < length; i++) {
5398 if (dst[i] == src[i]) continue;
5399 expected_changed = true;
5400 if (dir == ASCII_TO_LOWER) {
5401 ASSERT('A' <= src[i] && src[i] <= 'Z');
5402 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5403 } else {
5404 ASSERT(dir == ASCII_TO_UPPER);
5405 ASSERT('a' <= src[i] && src[i] <= 'z');
5406 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5407 }
5408 }
5409 ASSERT(expected_changed == changed);
5410 }
5411#endif
5412};
5413
5414
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005415struct ToLowerTraits {
5416 typedef unibrow::ToLowercase UnibrowConverter;
5417
lrn@chromium.org303ada72010-10-27 09:33:13 +00005418 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005419};
5420
5421
5422struct ToUpperTraits {
5423 typedef unibrow::ToUppercase UnibrowConverter;
5424
lrn@chromium.org303ada72010-10-27 09:33:13 +00005425 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005426};
5427
5428} // namespace
5429
5430
5431template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005432MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005433 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005434 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005436 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005437 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005438 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 if (length == 0) return s;
5443
5444 // Simpler handling of ascii strings.
5445 //
5446 // NOTE: This assumes that the upper/lower case of an ascii
5447 // character is also ascii. This is currently the case, but it
5448 // might break in the future if we implement more context and locale
5449 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005450 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005451 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005453 if (!maybe_o->ToObject(&o)) return maybe_o;
5454 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005455 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005456 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005457 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458 return has_changed_character ? result : s;
5459 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005460
lrn@chromium.org303ada72010-10-27 09:33:13 +00005461 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005462 { MaybeObject* maybe_answer =
5463 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005464 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5465 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005466 if (answer->IsSmi()) {
5467 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005468 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005469 ConvertCaseHelper(isolate,
5470 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005474 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475}
5476
5477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005478RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005479 return ConvertCase<ToLowerTraits>(
5480 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481}
5482
5483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005484RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005485 return ConvertCase<ToUpperTraits>(
5486 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487}
5488
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005489
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005490static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5491 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5492}
5493
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005495RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005496 NoHandleAllocation ha;
5497 ASSERT(args.length() == 3);
5498
5499 CONVERT_CHECKED(String, s, args[0]);
5500 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5501 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5502
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005503 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005504 int length = s->length();
5505
5506 int left = 0;
5507 if (trimLeft) {
5508 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5509 left++;
5510 }
5511 }
5512
5513 int right = length;
5514 if (trimRight) {
5515 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5516 right--;
5517 }
5518 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005519 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005520}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005522
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005523template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005524void FindStringIndices(Isolate* isolate,
5525 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005526 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005527 ZoneList<int>* indices,
5528 unsigned int limit) {
5529 ASSERT(limit > 0);
5530 // Collect indices of pattern in subject, and the end-of-string index.
5531 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005532 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005533 int pattern_length = pattern.length();
5534 int index = 0;
5535 while (limit > 0) {
5536 index = search.Search(subject, index);
5537 if (index < 0) return;
5538 indices->Add(index);
5539 index += pattern_length;
5540 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005541 }
5542}
5543
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005545RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005546 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005547 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005548 CONVERT_ARG_CHECKED(String, subject, 0);
5549 CONVERT_ARG_CHECKED(String, pattern, 1);
5550 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5551
5552 int subject_length = subject->length();
5553 int pattern_length = pattern->length();
5554 RUNTIME_ASSERT(pattern_length > 0);
5555
5556 // The limit can be very large (0xffffffffu), but since the pattern
5557 // isn't empty, we can never create more parts than ~half the length
5558 // of the subject.
5559
5560 if (!subject->IsFlat()) FlattenString(subject);
5561
5562 static const int kMaxInitialListCapacity = 16;
5563
5564 ZoneScope scope(DELETE_ON_EXIT);
5565
5566 // Find (up to limit) indices of separator and end-of-string in subject
5567 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5568 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005569 if (!pattern->IsFlat()) FlattenString(pattern);
5570
5571 // No allocation block.
5572 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005573 AssertNoAllocation nogc;
5574 if (subject->IsAsciiRepresentation()) {
5575 Vector<const char> subject_vector = subject->ToAsciiVector();
5576 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005577 FindStringIndices(isolate,
5578 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005579 pattern->ToAsciiVector(),
5580 &indices,
5581 limit);
5582 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005583 FindStringIndices(isolate,
5584 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005585 pattern->ToUC16Vector(),
5586 &indices,
5587 limit);
5588 }
5589 } else {
5590 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5591 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592 FindStringIndices(isolate,
5593 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005594 pattern->ToAsciiVector(),
5595 &indices,
5596 limit);
5597 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598 FindStringIndices(isolate,
5599 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005600 pattern->ToUC16Vector(),
5601 &indices,
5602 limit);
5603 }
5604 }
5605 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005606
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005607 if (static_cast<uint32_t>(indices.length()) < limit) {
5608 indices.Add(subject_length);
5609 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005610
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005611 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612
5613 // Create JSArray of substrings separated by separator.
5614 int part_count = indices.length();
5615
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005616 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005617 result->set_length(Smi::FromInt(part_count));
5618
5619 ASSERT(result->HasFastElements());
5620
5621 if (part_count == 1 && indices.at(0) == subject_length) {
5622 FixedArray::cast(result->elements())->set(0, *subject);
5623 return *result;
5624 }
5625
5626 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5627 int part_start = 0;
5628 for (int i = 0; i < part_count; i++) {
5629 HandleScope local_loop_handle;
5630 int part_end = indices.at(i);
5631 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005632 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005633 elements->set(i, *substring);
5634 part_start = part_end + pattern_length;
5635 }
5636
5637 return *result;
5638}
5639
5640
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005641// Copies ascii characters to the given fixed array looking up
5642// one-char strings in the cache. Gives up on the first char that is
5643// not in the cache and fills the remainder with smi zeros. Returns
5644// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005645static int CopyCachedAsciiCharsToArray(Heap* heap,
5646 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005647 FixedArray* elements,
5648 int length) {
5649 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005650 FixedArray* ascii_cache = heap->single_character_string_cache();
5651 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005652 int i;
5653 for (i = 0; i < length; ++i) {
5654 Object* value = ascii_cache->get(chars[i]);
5655 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005656 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005657 elements->set(i, value, SKIP_WRITE_BARRIER);
5658 }
5659 if (i < length) {
5660 ASSERT(Smi::FromInt(0) == 0);
5661 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5662 }
5663#ifdef DEBUG
5664 for (int j = 0; j < length; ++j) {
5665 Object* element = elements->get(j);
5666 ASSERT(element == Smi::FromInt(0) ||
5667 (element->IsString() && String::cast(element)->LooksValid()));
5668 }
5669#endif
5670 return i;
5671}
5672
5673
5674// Converts a String to JSArray.
5675// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005676RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005678 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005679 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005680 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681
5682 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005683 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684
5685 Handle<FixedArray> elements;
5686 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005687 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005688 { MaybeObject* maybe_obj =
5689 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005690 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005692 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005693
5694 Vector<const char> chars = s->ToAsciiVector();
5695 // Note, this will initialize all elements (not only the prefix)
5696 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005697 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5698 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005699 *elements,
5700 length);
5701
5702 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005703 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5704 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005705 }
5706 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005707 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005709 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5710 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711 }
5712 }
5713
5714#ifdef DEBUG
5715 for (int i = 0; i < length; ++i) {
5716 ASSERT(String::cast(elements->get(i))->length() == 1);
5717 }
5718#endif
5719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005721}
5722
5723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005724RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005725 NoHandleAllocation ha;
5726 ASSERT(args.length() == 1);
5727 CONVERT_CHECKED(String, value, args[0]);
5728 return value->ToObject();
5729}
5730
5731
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005732bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005733 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005735 return char_length == 0;
5736}
5737
5738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005739RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 NoHandleAllocation ha;
5741 ASSERT(args.length() == 1);
5742
5743 Object* number = args[0];
5744 RUNTIME_ASSERT(number->IsNumber());
5745
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005747}
5748
5749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005750RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005751 NoHandleAllocation ha;
5752 ASSERT(args.length() == 1);
5753
5754 Object* number = args[0];
5755 RUNTIME_ASSERT(number->IsNumber());
5756
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005757 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005758}
5759
5760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005761RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005762 NoHandleAllocation ha;
5763 ASSERT(args.length() == 1);
5764
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005765 CONVERT_DOUBLE_CHECKED(number, args[0]);
5766
5767 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5768 if (number > 0 && number <= Smi::kMaxValue) {
5769 return Smi::FromInt(static_cast<int>(number));
5770 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005772}
5773
5774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005775RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005776 NoHandleAllocation ha;
5777 ASSERT(args.length() == 1);
5778
5779 CONVERT_DOUBLE_CHECKED(number, args[0]);
5780
5781 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5782 if (number > 0 && number <= Smi::kMaxValue) {
5783 return Smi::FromInt(static_cast<int>(number));
5784 }
5785
5786 double double_value = DoubleToInteger(number);
5787 // Map both -0 and +0 to +0.
5788 if (double_value == 0) double_value = 0;
5789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005791}
5792
5793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005794RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005795 NoHandleAllocation ha;
5796 ASSERT(args.length() == 1);
5797
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005798 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005799 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005800}
5801
5802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005803RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005804 NoHandleAllocation ha;
5805 ASSERT(args.length() == 1);
5806
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005807 CONVERT_DOUBLE_CHECKED(number, args[0]);
5808
5809 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5810 if (number > 0 && number <= Smi::kMaxValue) {
5811 return Smi::FromInt(static_cast<int>(number));
5812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814}
5815
5816
ager@chromium.org870a0b62008-11-04 11:43:05 +00005817// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5818// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005819RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005820 NoHandleAllocation ha;
5821 ASSERT(args.length() == 1);
5822
5823 Object* obj = args[0];
5824 if (obj->IsSmi()) {
5825 return obj;
5826 }
5827 if (obj->IsHeapNumber()) {
5828 double value = HeapNumber::cast(obj)->value();
5829 int int_value = FastD2I(value);
5830 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5831 return Smi::FromInt(int_value);
5832 }
5833 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005834 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005835}
5836
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005838RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005839 NoHandleAllocation ha;
5840 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005841 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005842}
5843
5844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005845RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 NoHandleAllocation ha;
5847 ASSERT(args.length() == 2);
5848
5849 CONVERT_DOUBLE_CHECKED(x, args[0]);
5850 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005851 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005852}
5853
5854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005855RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 NoHandleAllocation ha;
5857 ASSERT(args.length() == 2);
5858
5859 CONVERT_DOUBLE_CHECKED(x, args[0]);
5860 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005861 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005862}
5863
5864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005865RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005866 NoHandleAllocation ha;
5867 ASSERT(args.length() == 2);
5868
5869 CONVERT_DOUBLE_CHECKED(x, args[0]);
5870 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872}
5873
5874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005875RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 1);
5878
5879 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881}
5882
5883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005884RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005885 NoHandleAllocation ha;
5886 ASSERT(args.length() == 0);
5887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005888 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005889}
5890
5891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005892RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893 NoHandleAllocation ha;
5894 ASSERT(args.length() == 2);
5895
5896 CONVERT_DOUBLE_CHECKED(x, args[0]);
5897 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005899}
5900
5901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005902RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 NoHandleAllocation ha;
5904 ASSERT(args.length() == 2);
5905
5906 CONVERT_DOUBLE_CHECKED(x, args[0]);
5907 CONVERT_DOUBLE_CHECKED(y, args[1]);
5908
ager@chromium.org3811b432009-10-28 14:53:37 +00005909 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005910 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912}
5913
5914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 NoHandleAllocation ha;
5917 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 CONVERT_CHECKED(String, str1, args[0]);
5919 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 isolate->counters()->string_add_runtime()->Increment();
5921 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922}
5923
5924
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005925template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005926static inline void StringBuilderConcatHelper(String* special,
5927 sinkchar* sink,
5928 FixedArray* fixed_array,
5929 int array_length) {
5930 int position = 0;
5931 for (int i = 0; i < array_length; i++) {
5932 Object* element = fixed_array->get(i);
5933 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005934 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005935 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005936 int pos;
5937 int len;
5938 if (encoded_slice > 0) {
5939 // Position and length encoded in one smi.
5940 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5941 len = StringBuilderSubstringLength::decode(encoded_slice);
5942 } else {
5943 // Position and length encoded in two smis.
5944 Object* obj = fixed_array->get(++i);
5945 ASSERT(obj->IsSmi());
5946 pos = Smi::cast(obj)->value();
5947 len = -encoded_slice;
5948 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005949 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005950 sink + position,
5951 pos,
5952 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005953 position += len;
5954 } else {
5955 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005956 int element_length = string->length();
5957 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005958 position += element_length;
5959 }
5960 }
5961}
5962
5963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005964RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005965 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005966 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005968 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005970 return Failure::OutOfMemoryException();
5971 }
5972 int array_length = Smi::cast(args[1])->value();
5973 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005974
5975 // This assumption is used by the slice encoding in one or two smis.
5976 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5977
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005978 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005980 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 }
5982 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005983 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986
5987 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005988 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 } else if (array_length == 1) {
5990 Object* first = fixed_array->get(0);
5991 if (first->IsString()) return first;
5992 }
5993
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005994 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 int position = 0;
5996 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005997 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 Object* elt = fixed_array->get(i);
5999 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006000 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006001 int smi_value = Smi::cast(elt)->value();
6002 int pos;
6003 int len;
6004 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006005 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006006 pos = StringBuilderSubstringPosition::decode(smi_value);
6007 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006008 } else {
6009 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006010 len = -smi_value;
6011 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006012 i++;
6013 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006014 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006015 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006016 Object* next_smi = fixed_array->get(i);
6017 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006019 }
6020 pos = Smi::cast(next_smi)->value();
6021 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006022 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006025 ASSERT(pos >= 0);
6026 ASSERT(len >= 0);
6027 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006028 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006029 }
6030 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 } else if (elt->IsString()) {
6032 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006034 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006035 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006039 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006041 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006042 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006043 return Failure::OutOfMemoryException();
6044 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006045 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046 }
6047
6048 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 { MaybeObject* maybe_object =
6053 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006054 if (!maybe_object->ToObject(&object)) return maybe_object;
6055 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006056 SeqAsciiString* answer = SeqAsciiString::cast(object);
6057 StringBuilderConcatHelper(special,
6058 answer->GetChars(),
6059 fixed_array,
6060 array_length);
6061 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063 { MaybeObject* maybe_object =
6064 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006065 if (!maybe_object->ToObject(&object)) return maybe_object;
6066 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006067 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6068 StringBuilderConcatHelper(special,
6069 answer->GetChars(),
6070 fixed_array,
6071 array_length);
6072 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006073 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074}
6075
6076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006077RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006078 NoHandleAllocation ha;
6079 ASSERT(args.length() == 3);
6080 CONVERT_CHECKED(JSArray, array, args[0]);
6081 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006082 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006083 return Failure::OutOfMemoryException();
6084 }
6085 int array_length = Smi::cast(args[1])->value();
6086 CONVERT_CHECKED(String, separator, args[2]);
6087
6088 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006089 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006090 }
6091 FixedArray* fixed_array = FixedArray::cast(array->elements());
6092 if (fixed_array->length() < array_length) {
6093 array_length = fixed_array->length();
6094 }
6095
6096 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006097 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006098 } else if (array_length == 1) {
6099 Object* first = fixed_array->get(0);
6100 if (first->IsString()) return first;
6101 }
6102
6103 int separator_length = separator->length();
6104 int max_nof_separators =
6105 (String::kMaxLength + separator_length - 1) / separator_length;
6106 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006107 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006108 return Failure::OutOfMemoryException();
6109 }
6110 int length = (array_length - 1) * separator_length;
6111 for (int i = 0; i < array_length; i++) {
6112 Object* element_obj = fixed_array->get(i);
6113 if (!element_obj->IsString()) {
6114 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006115 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006116 }
6117 String* element = String::cast(element_obj);
6118 int increment = element->length();
6119 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006121 return Failure::OutOfMemoryException();
6122 }
6123 length += increment;
6124 }
6125
6126 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 { MaybeObject* maybe_object =
6128 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006129 if (!maybe_object->ToObject(&object)) return maybe_object;
6130 }
6131 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6132
6133 uc16* sink = answer->GetChars();
6134#ifdef DEBUG
6135 uc16* end = sink + length;
6136#endif
6137
6138 String* first = String::cast(fixed_array->get(0));
6139 int first_length = first->length();
6140 String::WriteToFlat(first, sink, 0, first_length);
6141 sink += first_length;
6142
6143 for (int i = 1; i < array_length; i++) {
6144 ASSERT(sink + separator_length <= end);
6145 String::WriteToFlat(separator, sink, 0, separator_length);
6146 sink += separator_length;
6147
6148 String* element = String::cast(fixed_array->get(i));
6149 int element_length = element->length();
6150 ASSERT(sink + element_length <= end);
6151 String::WriteToFlat(element, sink, 0, element_length);
6152 sink += element_length;
6153 }
6154 ASSERT(sink == end);
6155
6156 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6157 return answer;
6158}
6159
6160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006161RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162 NoHandleAllocation ha;
6163 ASSERT(args.length() == 2);
6164
6165 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6166 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006167 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168}
6169
6170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006171RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172 NoHandleAllocation ha;
6173 ASSERT(args.length() == 2);
6174
6175 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6176 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006177 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178}
6179
6180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006181RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006182 NoHandleAllocation ha;
6183 ASSERT(args.length() == 2);
6184
6185 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6186 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006187 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188}
6189
6190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006191RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006192 NoHandleAllocation ha;
6193 ASSERT(args.length() == 1);
6194
6195 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006196 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197}
6198
6199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006200RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201 NoHandleAllocation ha;
6202 ASSERT(args.length() == 2);
6203
6204 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6205 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006206 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207}
6208
6209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006210RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006211 NoHandleAllocation ha;
6212 ASSERT(args.length() == 2);
6213
6214 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6215 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006216 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217}
6218
6219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006220RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221 NoHandleAllocation ha;
6222 ASSERT(args.length() == 2);
6223
6224 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6225 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227}
6228
6229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006230RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231 NoHandleAllocation ha;
6232 ASSERT(args.length() == 2);
6233
6234 CONVERT_DOUBLE_CHECKED(x, args[0]);
6235 CONVERT_DOUBLE_CHECKED(y, args[1]);
6236 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6237 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6238 if (x == y) return Smi::FromInt(EQUAL);
6239 Object* result;
6240 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6241 result = Smi::FromInt(EQUAL);
6242 } else {
6243 result = Smi::FromInt(NOT_EQUAL);
6244 }
6245 return result;
6246}
6247
6248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006249RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250 NoHandleAllocation ha;
6251 ASSERT(args.length() == 2);
6252
6253 CONVERT_CHECKED(String, x, args[0]);
6254 CONVERT_CHECKED(String, y, args[1]);
6255
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006256 bool not_equal = !x->Equals(y);
6257 // This is slightly convoluted because the value that signifies
6258 // equality is 0 and inequality is 1 so we have to negate the result
6259 // from String::Equals.
6260 ASSERT(not_equal == 0 || not_equal == 1);
6261 STATIC_CHECK(EQUAL == 0);
6262 STATIC_CHECK(NOT_EQUAL == 1);
6263 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006267RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268 NoHandleAllocation ha;
6269 ASSERT(args.length() == 3);
6270
6271 CONVERT_DOUBLE_CHECKED(x, args[0]);
6272 CONVERT_DOUBLE_CHECKED(y, args[1]);
6273 if (isnan(x) || isnan(y)) return args[2];
6274 if (x == y) return Smi::FromInt(EQUAL);
6275 if (isless(x, y)) return Smi::FromInt(LESS);
6276 return Smi::FromInt(GREATER);
6277}
6278
6279
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006280// Compare two Smis as if they were converted to strings and then
6281// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006282RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006283 NoHandleAllocation ha;
6284 ASSERT(args.length() == 2);
6285
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006286 // Extract the integer values from the Smis.
6287 CONVERT_CHECKED(Smi, x, args[0]);
6288 CONVERT_CHECKED(Smi, y, args[1]);
6289 int x_value = x->value();
6290 int y_value = y->value();
6291
6292 // If the integers are equal so are the string representations.
6293 if (x_value == y_value) return Smi::FromInt(EQUAL);
6294
6295 // If one of the integers are zero the normal integer order is the
6296 // same as the lexicographic order of the string representations.
6297 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6298
ager@chromium.org32912102009-01-16 10:38:43 +00006299 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006300 // smallest because the char code of '-' is less than the char code
6301 // of any digit. Otherwise, we make both values positive.
6302 if (x_value < 0 || y_value < 0) {
6303 if (y_value >= 0) return Smi::FromInt(LESS);
6304 if (x_value >= 0) return Smi::FromInt(GREATER);
6305 x_value = -x_value;
6306 y_value = -y_value;
6307 }
6308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 // Arrays for the individual characters of the two Smis. Smis are
6310 // 31 bit integers and 10 decimal digits are therefore enough.
6311 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6312 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6313 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6314
6315
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006316 // Convert the integers to arrays of their decimal digits.
6317 int x_index = 0;
6318 int y_index = 0;
6319 while (x_value > 0) {
6320 x_elms[x_index++] = x_value % 10;
6321 x_value /= 10;
6322 }
6323 while (y_value > 0) {
6324 y_elms[y_index++] = y_value % 10;
6325 y_value /= 10;
6326 }
6327
6328 // Loop through the arrays of decimal digits finding the first place
6329 // where they differ.
6330 while (--x_index >= 0 && --y_index >= 0) {
6331 int diff = x_elms[x_index] - y_elms[y_index];
6332 if (diff != 0) return Smi::FromInt(diff);
6333 }
6334
6335 // If one array is a suffix of the other array, the longest array is
6336 // the representation of the largest of the Smis in the
6337 // lexicographic ordering.
6338 return Smi::FromInt(x_index - y_index);
6339}
6340
6341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006342static Object* StringInputBufferCompare(RuntimeState* state,
6343 String* x,
6344 String* y) {
6345 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6346 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006347 bufx.Reset(x);
6348 bufy.Reset(y);
6349 while (bufx.has_more() && bufy.has_more()) {
6350 int d = bufx.GetNext() - bufy.GetNext();
6351 if (d < 0) return Smi::FromInt(LESS);
6352 else if (d > 0) return Smi::FromInt(GREATER);
6353 }
6354
6355 // x is (non-trivial) prefix of y:
6356 if (bufy.has_more()) return Smi::FromInt(LESS);
6357 // y is prefix of x:
6358 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6359}
6360
6361
6362static Object* FlatStringCompare(String* x, String* y) {
6363 ASSERT(x->IsFlat());
6364 ASSERT(y->IsFlat());
6365 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6366 int prefix_length = x->length();
6367 if (y->length() < prefix_length) {
6368 prefix_length = y->length();
6369 equal_prefix_result = Smi::FromInt(GREATER);
6370 } else if (y->length() > prefix_length) {
6371 equal_prefix_result = Smi::FromInt(LESS);
6372 }
6373 int r;
6374 if (x->IsAsciiRepresentation()) {
6375 Vector<const char> x_chars = x->ToAsciiVector();
6376 if (y->IsAsciiRepresentation()) {
6377 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006378 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006379 } else {
6380 Vector<const uc16> y_chars = y->ToUC16Vector();
6381 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6382 }
6383 } else {
6384 Vector<const uc16> x_chars = x->ToUC16Vector();
6385 if (y->IsAsciiRepresentation()) {
6386 Vector<const char> y_chars = y->ToAsciiVector();
6387 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6388 } else {
6389 Vector<const uc16> y_chars = y->ToUC16Vector();
6390 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6391 }
6392 }
6393 Object* result;
6394 if (r == 0) {
6395 result = equal_prefix_result;
6396 } else {
6397 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006399 ASSERT(result ==
6400 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 return result;
6402}
6403
6404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006405RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006406 NoHandleAllocation ha;
6407 ASSERT(args.length() == 2);
6408
6409 CONVERT_CHECKED(String, x, args[0]);
6410 CONVERT_CHECKED(String, y, args[1]);
6411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006412 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006414 // A few fast case tests before we flatten.
6415 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006416 if (y->length() == 0) {
6417 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006418 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006419 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 return Smi::FromInt(LESS);
6421 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006422
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006423 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006424 if (d < 0) return Smi::FromInt(LESS);
6425 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426
lrn@chromium.org303ada72010-10-27 09:33:13 +00006427 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006431 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006432 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006435 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006436 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006437}
6438
6439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006440RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441 NoHandleAllocation ha;
6442 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006443 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444
6445 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006447}
6448
6449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006450RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 NoHandleAllocation ha;
6452 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006453 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006454
6455 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457}
6458
6459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006460RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461 NoHandleAllocation ha;
6462 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464
6465 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006466 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006467}
6468
6469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470static const double kPiDividedBy4 = 0.78539816339744830962;
6471
6472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006473RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 NoHandleAllocation ha;
6475 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006476 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477
6478 CONVERT_DOUBLE_CHECKED(x, args[0]);
6479 CONVERT_DOUBLE_CHECKED(y, args[1]);
6480 double result;
6481 if (isinf(x) && isinf(y)) {
6482 // Make sure that the result in case of two infinite arguments
6483 // is a multiple of Pi / 4. The sign of the result is determined
6484 // by the first argument (x) and the sign of the second argument
6485 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006486 int multiplier = (x < 0) ? -1 : 1;
6487 if (y < 0) multiplier *= 3;
6488 result = multiplier * kPiDividedBy4;
6489 } else {
6490 result = atan2(x, y);
6491 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500
6501 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503}
6504
6505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006506RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507 NoHandleAllocation ha;
6508 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510
6511 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006512 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513}
6514
6515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006516RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517 NoHandleAllocation ha;
6518 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006519 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520
6521 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006522 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006523}
6524
6525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006526RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527 NoHandleAllocation ha;
6528 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006530
6531 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006532 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533}
6534
6535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006536RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006539 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540
6541 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550
6551 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006552
6553 // If the second argument is a smi, it is much faster to call the
6554 // custom powi() function than the generic pow().
6555 if (args[1]->IsSmi()) {
6556 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006557 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006558 }
6559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562}
6563
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006564// Fast version of Math.pow if we know that y is not an integer and
6565// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 2);
6569 CONVERT_DOUBLE_CHECKED(x, args[0]);
6570 CONVERT_DOUBLE_CHECKED(y, args[1]);
6571 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006572 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006573 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006575 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577 }
6578}
6579
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006581RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006586 if (!args[0]->IsHeapNumber()) {
6587 // Must be smi. Return the argument unchanged for all the other types
6588 // to make fuzz-natives test happy.
6589 return args[0];
6590 }
6591
6592 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6593
6594 double value = number->value();
6595 int exponent = number->get_exponent();
6596 int sign = number->get_sign();
6597
6598 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6599 // should be rounded to 2^30, which is not smi.
6600 if (!sign && exponent <= kSmiValueSize - 3) {
6601 return Smi::FromInt(static_cast<int>(value + 0.5));
6602 }
6603
6604 // If the magnitude is big enough, there's no place for fraction part. If we
6605 // try to add 0.5 to this number, 1.0 will be added instead.
6606 if (exponent >= 52) {
6607 return number;
6608 }
6609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006610 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006611
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006612 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614}
6615
6616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006617RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 NoHandleAllocation ha;
6619 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006620 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621
6622 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624}
6625
6626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006627RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 NoHandleAllocation ha;
6629 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006630 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631
6632 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641
6642 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006643 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644}
6645
6646
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006647static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006648 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6649 181, 212, 243, 273, 304, 334};
6650 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6651 182, 213, 244, 274, 305, 335};
6652
6653 year += month / 12;
6654 month %= 12;
6655 if (month < 0) {
6656 year--;
6657 month += 12;
6658 }
6659
6660 ASSERT(month >= 0);
6661 ASSERT(month < 12);
6662
6663 // year_delta is an arbitrary number such that:
6664 // a) year_delta = -1 (mod 400)
6665 // b) year + year_delta > 0 for years in the range defined by
6666 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6667 // Jan 1 1970. This is required so that we don't run into integer
6668 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006669 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006670 // operations.
6671 static const int year_delta = 399999;
6672 static const int base_day = 365 * (1970 + year_delta) +
6673 (1970 + year_delta) / 4 -
6674 (1970 + year_delta) / 100 +
6675 (1970 + year_delta) / 400;
6676
6677 int year1 = year + year_delta;
6678 int day_from_year = 365 * year1 +
6679 year1 / 4 -
6680 year1 / 100 +
6681 year1 / 400 -
6682 base_day;
6683
6684 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006685 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006686 }
6687
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006688 return day_from_year + day_from_month_leap[month] + day - 1;
6689}
6690
6691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006692RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006693 NoHandleAllocation ha;
6694 ASSERT(args.length() == 3);
6695
6696 CONVERT_SMI_CHECKED(year, args[0]);
6697 CONVERT_SMI_CHECKED(month, args[1]);
6698 CONVERT_SMI_CHECKED(date, args[2]);
6699
6700 return Smi::FromInt(MakeDay(year, month, date));
6701}
6702
6703
6704static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6705static const int kDaysIn4Years = 4 * 365 + 1;
6706static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6707static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6708static const int kDays1970to2000 = 30 * 365 + 7;
6709static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6710 kDays1970to2000;
6711static const int kYearsOffset = 400000;
6712
6713static const char kDayInYear[] = {
6714 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6715 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6716 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6717 22, 23, 24, 25, 26, 27, 28,
6718 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6719 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6721 22, 23, 24, 25, 26, 27, 28, 29, 30,
6722 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6723 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6724 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6725 22, 23, 24, 25, 26, 27, 28, 29, 30,
6726 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6727 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6728 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6729 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6730 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6731 22, 23, 24, 25, 26, 27, 28, 29, 30,
6732 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6733 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6734 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6735 22, 23, 24, 25, 26, 27, 28, 29, 30,
6736 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6737 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6738
6739 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6740 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6741 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6742 22, 23, 24, 25, 26, 27, 28,
6743 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6744 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6745 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6746 22, 23, 24, 25, 26, 27, 28, 29, 30,
6747 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6748 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6749 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6750 22, 23, 24, 25, 26, 27, 28, 29, 30,
6751 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6752 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6753 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6754 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6755 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6756 22, 23, 24, 25, 26, 27, 28, 29, 30,
6757 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6758 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6759 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6760 22, 23, 24, 25, 26, 27, 28, 29, 30,
6761 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6762 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6763
6764 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6765 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6766 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6767 22, 23, 24, 25, 26, 27, 28, 29,
6768 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6769 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6770 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6771 22, 23, 24, 25, 26, 27, 28, 29, 30,
6772 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6773 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6774 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6775 22, 23, 24, 25, 26, 27, 28, 29, 30,
6776 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6777 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6778 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6779 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6780 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6781 22, 23, 24, 25, 26, 27, 28, 29, 30,
6782 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6783 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6784 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6785 22, 23, 24, 25, 26, 27, 28, 29, 30,
6786 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6787 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6788
6789 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6790 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6791 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6792 22, 23, 24, 25, 26, 27, 28,
6793 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6794 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6795 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6796 22, 23, 24, 25, 26, 27, 28, 29, 30,
6797 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6798 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6799 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6800 22, 23, 24, 25, 26, 27, 28, 29, 30,
6801 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6802 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6803 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6804 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6805 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6806 22, 23, 24, 25, 26, 27, 28, 29, 30,
6807 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6808 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6809 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6810 22, 23, 24, 25, 26, 27, 28, 29, 30,
6811 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6812 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6813
6814static const char kMonthInYear[] = {
6815 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,
6816 0, 0, 0, 0, 0, 0,
6817 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,
6818 1, 1, 1,
6819 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,
6820 2, 2, 2, 2, 2, 2,
6821 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,
6822 3, 3, 3, 3, 3,
6823 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,
6824 4, 4, 4, 4, 4, 4,
6825 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,
6826 5, 5, 5, 5, 5,
6827 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,
6828 6, 6, 6, 6, 6, 6,
6829 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,
6830 7, 7, 7, 7, 7, 7,
6831 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,
6832 8, 8, 8, 8, 8,
6833 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,
6834 9, 9, 9, 9, 9, 9,
6835 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6836 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6837 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6838 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6839
6840 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,
6841 0, 0, 0, 0, 0, 0,
6842 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,
6843 1, 1, 1,
6844 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,
6845 2, 2, 2, 2, 2, 2,
6846 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,
6847 3, 3, 3, 3, 3,
6848 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,
6849 4, 4, 4, 4, 4, 4,
6850 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,
6851 5, 5, 5, 5, 5,
6852 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,
6853 6, 6, 6, 6, 6, 6,
6854 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,
6855 7, 7, 7, 7, 7, 7,
6856 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,
6857 8, 8, 8, 8, 8,
6858 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,
6859 9, 9, 9, 9, 9, 9,
6860 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6861 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6862 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6863 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6864
6865 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,
6866 0, 0, 0, 0, 0, 0,
6867 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,
6868 1, 1, 1, 1,
6869 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,
6870 2, 2, 2, 2, 2, 2,
6871 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,
6872 3, 3, 3, 3, 3,
6873 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,
6874 4, 4, 4, 4, 4, 4,
6875 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,
6876 5, 5, 5, 5, 5,
6877 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,
6878 6, 6, 6, 6, 6, 6,
6879 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,
6880 7, 7, 7, 7, 7, 7,
6881 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,
6882 8, 8, 8, 8, 8,
6883 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,
6884 9, 9, 9, 9, 9, 9,
6885 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6886 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6887 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6888 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6889
6890 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,
6891 0, 0, 0, 0, 0, 0,
6892 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,
6893 1, 1, 1,
6894 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,
6895 2, 2, 2, 2, 2, 2,
6896 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,
6897 3, 3, 3, 3, 3,
6898 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,
6899 4, 4, 4, 4, 4, 4,
6900 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,
6901 5, 5, 5, 5, 5,
6902 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,
6903 6, 6, 6, 6, 6, 6,
6904 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,
6905 7, 7, 7, 7, 7, 7,
6906 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,
6907 8, 8, 8, 8, 8,
6908 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,
6909 9, 9, 9, 9, 9, 9,
6910 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6911 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6912 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6913 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6914
6915
6916// This function works for dates from 1970 to 2099.
6917static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006918 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006919#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006920 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006921#endif
6922
6923 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6924 date %= kDaysIn4Years;
6925
6926 month = kMonthInYear[date];
6927 day = kDayInYear[date];
6928
6929 ASSERT(MakeDay(year, month, day) == save_date);
6930}
6931
6932
6933static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006934 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006935#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006936 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006937#endif
6938
6939 date += kDaysOffset;
6940 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6941 date %= kDaysIn400Years;
6942
6943 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6944
6945 date--;
6946 int yd1 = date / kDaysIn100Years;
6947 date %= kDaysIn100Years;
6948 year += 100 * yd1;
6949
6950 date++;
6951 int yd2 = date / kDaysIn4Years;
6952 date %= kDaysIn4Years;
6953 year += 4 * yd2;
6954
6955 date--;
6956 int yd3 = date / 365;
6957 date %= 365;
6958 year += yd3;
6959
6960 bool is_leap = (!yd1 || yd2) && !yd3;
6961
6962 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006963 ASSERT(is_leap || (date >= 0));
6964 ASSERT((date < 365) || (is_leap && (date < 366)));
6965 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6966 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6967 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006968
6969 if (is_leap) {
6970 day = kDayInYear[2*365 + 1 + date];
6971 month = kMonthInYear[2*365 + 1 + date];
6972 } else {
6973 day = kDayInYear[date];
6974 month = kMonthInYear[date];
6975 }
6976
6977 ASSERT(MakeDay(year, month, day) == save_date);
6978}
6979
6980
6981static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006982 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006983 if (date >= 0 && date < 32 * kDaysIn4Years) {
6984 DateYMDFromTimeAfter1970(date, year, month, day);
6985 } else {
6986 DateYMDFromTimeSlow(date, year, month, day);
6987 }
6988}
6989
6990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006991RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006992 NoHandleAllocation ha;
6993 ASSERT(args.length() == 2);
6994
6995 CONVERT_DOUBLE_CHECKED(t, args[0]);
6996 CONVERT_CHECKED(JSArray, res_array, args[1]);
6997
6998 int year, month, day;
6999 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007001 RUNTIME_ASSERT(res_array->elements()->map() ==
7002 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007003 FixedArray* elms = FixedArray::cast(res_array->elements());
7004 RUNTIME_ASSERT(elms->length() == 3);
7005
7006 elms->set(0, Smi::FromInt(year));
7007 elms->set(1, Smi::FromInt(month));
7008 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007011}
7012
7013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007014RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 3);
7017
7018 JSFunction* callee = JSFunction::cast(args[0]);
7019 Object** parameters = reinterpret_cast<Object**>(args[1]);
7020 const int length = Smi::cast(args[2])->value();
7021
lrn@chromium.org303ada72010-10-27 09:33:13 +00007022 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007023 { MaybeObject* maybe_result =
7024 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007025 if (!maybe_result->ToObject(&result)) return maybe_result;
7026 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007027 // Allocate the elements if needed.
7028 if (length > 0) {
7029 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007030 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007031 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007032 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7033 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007034
7035 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007036 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007038 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007039
7040 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007041 for (int i = 0; i < length; i++) {
7042 array->set(i, *--parameters, mode);
7043 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007044 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007045 }
7046 return result;
7047}
7048
7049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007050RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007052 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007053 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007054 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007055 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007057 // Allocate global closures in old space and allocate local closures
7058 // in new space. Additionally pretenure closures that are assigned
7059 // directly to properties.
7060 pretenure = pretenure || (context->global_context() == *context);
7061 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7064 context,
7065 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 return *result;
7067}
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069
7070static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7071 int* total_argc) {
7072 // Find frame containing arguments passed to the caller.
7073 JavaScriptFrameIterator it;
7074 JavaScriptFrame* frame = it.frame();
7075 List<JSFunction*> functions(2);
7076 frame->GetFunctions(&functions);
7077 if (functions.length() > 1) {
7078 int inlined_frame_index = functions.length() - 1;
7079 JSFunction* inlined_function = functions[inlined_frame_index];
7080 int args_count = inlined_function->shared()->formal_parameter_count();
7081 ScopedVector<SlotRef> args_slots(args_count);
7082 SlotRef::ComputeSlotMappingForArguments(frame,
7083 inlined_frame_index,
7084 &args_slots);
7085
7086 *total_argc = bound_argc + args_count;
7087 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7088 for (int i = 0; i < args_count; i++) {
7089 Handle<Object> val = args_slots[i].GetValue();
7090 param_data[bound_argc + i] = val.location();
7091 }
7092 return param_data;
7093 } else {
7094 it.AdvanceToArgumentsFrame();
7095 frame = it.frame();
7096 int args_count = frame->ComputeParametersCount();
7097
7098 *total_argc = bound_argc + args_count;
7099 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7100 for (int i = 0; i < args_count; i++) {
7101 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7102 param_data[bound_argc + i] = val.location();
7103 }
7104 return param_data;
7105 }
7106}
7107
7108
7109RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007110 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007111 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007112 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007113 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007114
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007115 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007116 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007117 int bound_argc = 0;
7118 if (!args[1]->IsNull()) {
7119 CONVERT_ARG_CHECKED(JSArray, params, 1);
7120 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007121 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007122 bound_argc = Smi::cast(params->length())->value();
7123 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007125 int total_argc = 0;
7126 SmartPointer<Object**> param_data =
7127 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007128 for (int i = 0; i < bound_argc; i++) {
7129 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007130 param_data[i] = val.location();
7131 }
7132
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007133 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007134 Handle<Object> result =
7135 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007136 if (exception) {
7137 return Failure::Exception();
7138 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007139
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007140 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007141 return *result;
7142}
7143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145static void TrySettingInlineConstructStub(Isolate* isolate,
7146 Handle<JSFunction> function) {
7147 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007148 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007149 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007150 }
7151 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007152 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007153 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007154 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007155 function->shared()->set_construct_stub(
7156 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007157 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007158 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007159}
7160
7161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007162RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007164 ASSERT(args.length() == 1);
7165
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007166 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007167
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007168 // If the constructor isn't a proper function we throw a type error.
7169 if (!constructor->IsJSFunction()) {
7170 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7171 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 isolate->factory()->NewTypeError("not_constructor", arguments);
7173 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007174 }
7175
7176 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007177
7178 // If function should not have prototype, construction is not allowed. In this
7179 // case generated code bailouts here, since function has no initial_map.
7180 if (!function->should_have_prototype()) {
7181 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7182 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007183 isolate->factory()->NewTypeError("not_constructor", arguments);
7184 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007185 }
7186
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007187#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007188 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007189 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 if (debug->StepInActive()) {
7191 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007192 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007193#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007195 if (function->has_initial_map()) {
7196 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007197 // The 'Function' function ignores the receiver object when
7198 // called using 'new' and creates a new JSFunction object that
7199 // is returned. The receiver object is only used for error
7200 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007201 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007202 // allocate JSFunctions since it does not properly initialize
7203 // the shared part of the function. Since the receiver is
7204 // ignored anyway, we use the global object as the receiver
7205 // instead of a new JSFunction object. This way, errors are
7206 // reported the same way whether or not 'Function' is called
7207 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007208 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007210 }
7211
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007212 // The function should be compiled for the optimization hints to be
7213 // available. We cannot use EnsureCompiled because that forces a
7214 // compilation through the shared function info which makes it
7215 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007217 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007218
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007219 if (!function->has_initial_map() &&
7220 shared->IsInobjectSlackTrackingInProgress()) {
7221 // The tracking is already in progress for another function. We can only
7222 // track one initial_map at a time, so we force the completion before the
7223 // function is called as a constructor for the first time.
7224 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007225 }
7226
7227 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7229 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007230 // Delay setting the stub if inobject slack tracking is in progress.
7231 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007232 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007233 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007235 isolate->counters()->constructed_objects()->Increment();
7236 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007237
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007238 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239}
7240
7241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007242RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007243 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007244 ASSERT(args.length() == 1);
7245
7246 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7247 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007248 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007249
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007250 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007251}
7252
7253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007254RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007255 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007256 ASSERT(args.length() == 1);
7257
7258 Handle<JSFunction> function = args.at<JSFunction>(0);
7259#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007260 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007262 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263 PrintF("]\n");
7264 }
7265#endif
7266
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007267 // Compile the target function. Here we compile using CompileLazyInLoop in
7268 // order to get the optimized version. This helps code like delta-blue
7269 // that calls performance-critical routines through constructors. A
7270 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7271 // direct call. Since the in-loop tracking takes place through CallICs
7272 // this means that things called through constructors are never known to
7273 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007275 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 return Failure::Exception();
7277 }
7278
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007279 // All done. Return the compiled code.
7280 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281 return function->code();
7282}
7283
7284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007285RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007287 ASSERT(args.length() == 1);
7288 Handle<JSFunction> function = args.at<JSFunction>(0);
7289 // If the function is not optimizable or debugger is active continue using the
7290 // code from the full compiler.
7291 if (!function->shared()->code()->optimizable() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007292 isolate->debug()->has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007293 if (FLAG_trace_opt) {
7294 PrintF("[failed to optimize ");
7295 function->PrintName();
7296 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7297 function->shared()->code()->optimizable() ? "T" : "F",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 isolate->debug()->has_break_points() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007299 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007300 function->ReplaceCode(function->shared()->code());
7301 return function->code();
7302 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007303 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007304 return function->code();
7305 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007306 if (FLAG_trace_opt) {
7307 PrintF("[failed to optimize ");
7308 function->PrintName();
7309 PrintF(": optimized compilation failed]\n");
7310 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007311 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007312 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007313}
7314
7315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007316RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007318 ASSERT(args.length() == 1);
7319 RUNTIME_ASSERT(args[0]->IsSmi());
7320 Deoptimizer::BailoutType type =
7321 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7323 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007324 int frames = deoptimizer->output_count();
7325
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007326 deoptimizer->MaterializeHeapNumbers();
7327 delete deoptimizer;
7328
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007329 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007330 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007331 for (int i = 0; i < frames - 1; i++) it.Advance();
7332 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007333
7334 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007336 Handle<Object> arguments;
7337 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007339 if (arguments.is_null()) {
7340 // FunctionGetArguments can't throw an exception, so cast away the
7341 // doubt with an assert.
7342 arguments = Handle<Object>(
7343 Accessors::FunctionGetArguments(*function,
7344 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 ASSERT(*arguments != isolate->heap()->null_value());
7346 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007347 }
7348 frame->SetExpression(i, *arguments);
7349 }
7350 }
7351
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007353 if (type == Deoptimizer::EAGER) {
7354 RUNTIME_ASSERT(function->IsOptimized());
7355 } else {
7356 RUNTIME_ASSERT(!function->IsOptimized());
7357 }
7358
7359 // Avoid doing too much work when running with --always-opt and keep
7360 // the optimized code around.
7361 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007363 }
7364
7365 // Count the number of optimized activations of the function.
7366 int activations = 0;
7367 while (!it.done()) {
7368 JavaScriptFrame* frame = it.frame();
7369 if (frame->is_optimized() && frame->function() == *function) {
7370 activations++;
7371 }
7372 it.Advance();
7373 }
7374
7375 // TODO(kasperl): For now, we cannot support removing the optimized
7376 // code when we have recursive invocations of the same function.
7377 if (activations == 0) {
7378 if (FLAG_trace_deopt) {
7379 PrintF("[removing optimized code for: ");
7380 function->PrintName();
7381 PrintF("]\n");
7382 }
7383 function->ReplaceCode(function->shared()->code());
7384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007386}
7387
7388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007389RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007390 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007391 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007398 ASSERT(args.length() == 1);
7399 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007400 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007401
7402 Deoptimizer::DeoptimizeFunction(*function);
7403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007405}
7406
7407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007410 ASSERT(args.length() == 1);
7411 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7412
7413 // We're not prepared to handle a function with arguments object.
7414 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7415
7416 // We have hit a back edge in an unoptimized frame for a function that was
7417 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007419 // Keep track of whether we've succeeded in optimizing.
7420 bool succeeded = unoptimized->optimizable();
7421 if (succeeded) {
7422 // If we are trying to do OSR when there are already optimized
7423 // activations of the function, it means (a) the function is directly or
7424 // indirectly recursive and (b) an optimized invocation has been
7425 // deoptimized so that we are currently in an unoptimized activation.
7426 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007427 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007428 while (succeeded && !it.done()) {
7429 JavaScriptFrame* frame = it.frame();
7430 succeeded = !frame->is_optimized() || frame->function() != *function;
7431 it.Advance();
7432 }
7433 }
7434
7435 int ast_id = AstNode::kNoNumber;
7436 if (succeeded) {
7437 // The top JS function is this one, the PC is somewhere in the
7438 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007439 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007440 JavaScriptFrame* frame = it.frame();
7441 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007442 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007443 ASSERT(unoptimized->contains(frame->pc()));
7444
7445 // Use linear search of the unoptimized code's stack check table to find
7446 // the AST id matching the PC.
7447 Address start = unoptimized->instruction_start();
7448 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007449 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007450 uint32_t table_length = Memory::uint32_at(table_cursor);
7451 table_cursor += kIntSize;
7452 for (unsigned i = 0; i < table_length; ++i) {
7453 // Table entries are (AST id, pc offset) pairs.
7454 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7455 if (pc_offset == target_pc_offset) {
7456 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7457 break;
7458 }
7459 table_cursor += 2 * kIntSize;
7460 }
7461 ASSERT(ast_id != AstNode::kNoNumber);
7462 if (FLAG_trace_osr) {
7463 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7464 function->PrintName();
7465 PrintF("]\n");
7466 }
7467
7468 // Try to compile the optimized code. A true return value from
7469 // CompileOptimized means that compilation succeeded, not necessarily
7470 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007471 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7472 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007473 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7474 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007475 if (data->OsrPcOffset()->value() >= 0) {
7476 if (FLAG_trace_osr) {
7477 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007478 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007479 }
7480 ASSERT(data->OsrAstId()->value() == ast_id);
7481 } else {
7482 // We may never generate the desired OSR entry if we emit an
7483 // early deoptimize.
7484 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007485 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 } else {
7487 succeeded = false;
7488 }
7489 }
7490
7491 // Revert to the original stack checks in the original unoptimized code.
7492 if (FLAG_trace_osr) {
7493 PrintF("[restoring original stack checks in ");
7494 function->PrintName();
7495 PrintF("]\n");
7496 }
7497 StackCheckStub check_stub;
7498 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007499 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007500 Deoptimizer::RevertStackCheckCode(*unoptimized,
7501 *check_code,
7502 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007503
7504 // Allow OSR only at nesting level zero again.
7505 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7506
7507 // If the optimization attempt succeeded, return the AST id tagged as a
7508 // smi. This tells the builtin that we need to translate the unoptimized
7509 // frame to an optimized one.
7510 if (succeeded) {
7511 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7512 return Smi::FromInt(ast_id);
7513 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007514 if (function->IsMarkedForLazyRecompilation()) {
7515 function->ReplaceCode(function->shared()->code());
7516 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007517 return Smi::FromInt(-1);
7518 }
7519}
7520
7521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007522RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007523 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007524 ASSERT(args.length() == 1);
7525 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7526 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7527}
7528
7529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007530RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007532 ASSERT(args.length() == 1);
7533 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7534 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7535}
7536
7537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007538RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007540 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007541
kasper.lund7276f142008-07-30 08:49:36 +00007542 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007543 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007544 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007545 { MaybeObject* maybe_result =
7546 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007547 if (!maybe_result->ToObject(&result)) return maybe_result;
7548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007549
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007550 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007551
kasper.lund7276f142008-07-30 08:49:36 +00007552 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553}
7554
lrn@chromium.org303ada72010-10-27 09:33:13 +00007555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7557 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007558 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007559 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007560 Object* js_object = object;
7561 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007562 MaybeObject* maybe_js_object = js_object->ToObject();
7563 if (!maybe_js_object->ToObject(&js_object)) {
7564 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7565 return maybe_js_object;
7566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 HandleScope scope(isolate);
7568 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007569 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007570 isolate->factory()->NewTypeError("with_expression",
7571 HandleVector(&handle, 1));
7572 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573 }
7574 }
7575
lrn@chromium.org303ada72010-10-27 09:33:13 +00007576 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007577 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7578 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007579 if (!maybe_result->ToObject(&result)) return maybe_result;
7580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007581
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007582 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007583 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007584
kasper.lund7276f142008-07-30 08:49:36 +00007585 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586}
7587
7588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007589RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007590 NoHandleAllocation ha;
7591 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007592 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007593}
7594
7595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007596RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007597 NoHandleAllocation ha;
7598 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007599 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007600}
7601
7602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007603RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007604 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605 ASSERT(args.length() == 2);
7606
7607 CONVERT_ARG_CHECKED(Context, context, 0);
7608 CONVERT_ARG_CHECKED(String, name, 1);
7609
7610 int index;
7611 PropertyAttributes attributes;
7612 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007613 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007614
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007615 // If the slot was not found the result is true.
7616 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007617 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007618 }
7619
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007620 // If the slot was found in a context, it should be DONT_DELETE.
7621 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007622 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007623 }
7624
7625 // The slot was found in a JSObject, either a context extension object,
7626 // the global object, or an arguments object. Try to delete it
7627 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7628 // which allows deleting all parameters in functions that mention
7629 // 'arguments', we do this even for the case of slots found on an
7630 // arguments object. The slot was found on an arguments object if the
7631 // index is non-negative.
7632 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7633 if (index >= 0) {
7634 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7635 } else {
7636 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7637 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007638}
7639
7640
ager@chromium.orga1645e22009-09-09 19:27:10 +00007641// A mechanism to return a pair of Object pointers in registers (if possible).
7642// How this is achieved is calling convention-dependent.
7643// All currently supported x86 compiles uses calling conventions that are cdecl
7644// variants where a 64-bit value is returned in two 32-bit registers
7645// (edx:eax on ia32, r1:r0 on ARM).
7646// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7647// In Win64 calling convention, a struct of two pointers is returned in memory,
7648// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007649#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007650struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007651 MaybeObject* x;
7652 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007653};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007654
lrn@chromium.org303ada72010-10-27 09:33:13 +00007655static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007656 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007657 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7658 // In Win64 they are assigned to a hidden first argument.
7659 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007660}
7661#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007662typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007663static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007664 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007665 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007666}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007667#endif
7668
7669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007670static inline MaybeObject* Unhole(Heap* heap,
7671 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007672 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007673 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7674 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007675 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007676}
7677
7678
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007679static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7680 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007681 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007682 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007683 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007684 JSFunction* context_extension_function =
7685 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007686 // If the holder isn't a context extension object, we just return it
7687 // as the receiver. This allows arguments objects to be used as
7688 // receivers, but only if they are put in the context scope chain
7689 // explicitly via a with-statement.
7690 Object* constructor = holder->map()->constructor();
7691 if (constructor != context_extension_function) return holder;
7692 // Fall back to using the global object as the receiver if the
7693 // property turns out to be a local variable allocated in a context
7694 // extension object - introduced via eval.
7695 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007696}
7697
7698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007699static ObjectPair LoadContextSlotHelper(Arguments args,
7700 Isolate* isolate,
7701 bool throw_error) {
7702 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007703 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007704
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007705 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007706 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007707 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007708 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007709 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007710
7711 int index;
7712 PropertyAttributes attributes;
7713 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007714 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007715
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007716 // If the index is non-negative, the slot has been found in a local
7717 // variable or a parameter. Read it from the context object or the
7718 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007719 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007720 // If the "property" we were looking for is a local variable or an
7721 // argument in a context, the receiver is the global object; see
7722 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007723 JSObject* receiver =
7724 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007725 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007726 ? Context::cast(*holder)->get(index)
7727 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007728 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729 }
7730
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007731 // If the holder is found, we read the property from it.
7732 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007733 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007734 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007735 JSObject* receiver;
7736 if (object->IsGlobalObject()) {
7737 receiver = GlobalObject::cast(object)->global_receiver();
7738 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007740 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007742 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007743 // No need to unhole the value here. This is taken care of by the
7744 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007745 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007746 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007747 }
7748
7749 if (throw_error) {
7750 // The property doesn't exist - throw exception.
7751 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 isolate->factory()->NewReferenceError("not_defined",
7753 HandleVector(&name, 1));
7754 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007755 } else {
7756 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007757 return MakePair(isolate->heap()->undefined_value(),
7758 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759 }
7760}
7761
7762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007763RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007764 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007765}
7766
7767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007769 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007770}
7771
7772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007773RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007774 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007775 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007777 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007779 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007780 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7781 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7782 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007783 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784
7785 int index;
7786 PropertyAttributes attributes;
7787 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007788 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789
7790 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007791 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007792 // Ignore if read_only variable.
7793 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007794 // Context is a fixed array and set cannot fail.
7795 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007796 } else if (strict_mode == kStrictMode) {
7797 // Setting read only property in strict mode.
7798 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007799 isolate->factory()->NewTypeError("strict_cannot_assign",
7800 HandleVector(&name, 1));
7801 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007802 }
7803 } else {
7804 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007805 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007806 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007807 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007808 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007809 return Failure::Exception();
7810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007811 }
7812 return *value;
7813 }
7814
7815 // Slow case: The property is not in a FixedArray context.
7816 // It is either in an JSObject extension context or it was not found.
7817 Handle<JSObject> context_ext;
7818
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007819 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007820 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007821 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007822 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007823 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007824 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007825
7826 if (strict_mode == kStrictMode) {
7827 // Throw in strict mode (assignment to undefined variable).
7828 Handle<Object> error =
7829 isolate->factory()->NewReferenceError(
7830 "not_defined", HandleVector(&name, 1));
7831 return isolate->Throw(*error);
7832 }
7833 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007835 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007836 }
7837
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007838 // Set the property, but ignore if read_only variable on the context
7839 // extension object itself.
7840 if ((attributes & READ_ONLY) == 0 ||
7841 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007842 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007843 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007844 SetProperty(context_ext, name, value, NONE, strict_mode));
7845 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007846 // Setting read only property in strict mode.
7847 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007848 isolate->factory()->NewTypeError(
7849 "strict_cannot_assign", HandleVector(&name, 1));
7850 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007851 }
7852 return *value;
7853}
7854
7855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007856RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007858 ASSERT(args.length() == 1);
7859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007861}
7862
7863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007864RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007866 ASSERT(args.length() == 1);
7867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869}
7870
7871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007872RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007873 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007874 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007875}
7876
7877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007878RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880 ASSERT(args.length() == 1);
7881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007882 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007883 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 isolate->factory()->NewReferenceError("not_defined",
7885 HandleVector(&name, 1));
7886 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887}
7888
7889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007890RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007891 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892
7893 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007894 if (isolate->stack_guard()->IsStackOverflow()) {
7895 NoHandleAllocation na;
7896 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007898
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007899 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007900}
7901
7902
7903// NOTE: These PrintXXX functions are defined for all builds (not just
7904// DEBUG builds) because we may want to be able to trace function
7905// calls in all modes.
7906static void PrintString(String* str) {
7907 // not uncommon to have empty strings
7908 if (str->length() > 0) {
7909 SmartPointer<char> s =
7910 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7911 PrintF("%s", *s);
7912 }
7913}
7914
7915
7916static void PrintObject(Object* obj) {
7917 if (obj->IsSmi()) {
7918 PrintF("%d", Smi::cast(obj)->value());
7919 } else if (obj->IsString() || obj->IsSymbol()) {
7920 PrintString(String::cast(obj));
7921 } else if (obj->IsNumber()) {
7922 PrintF("%g", obj->Number());
7923 } else if (obj->IsFailure()) {
7924 PrintF("<failure>");
7925 } else if (obj->IsUndefined()) {
7926 PrintF("<undefined>");
7927 } else if (obj->IsNull()) {
7928 PrintF("<null>");
7929 } else if (obj->IsTrue()) {
7930 PrintF("<true>");
7931 } else if (obj->IsFalse()) {
7932 PrintF("<false>");
7933 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007934 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007935 }
7936}
7937
7938
7939static int StackSize() {
7940 int n = 0;
7941 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7942 return n;
7943}
7944
7945
7946static void PrintTransition(Object* result) {
7947 // indentation
7948 { const int nmax = 80;
7949 int n = StackSize();
7950 if (n <= nmax)
7951 PrintF("%4d:%*s", n, n, "");
7952 else
7953 PrintF("%4d:%*s", n, nmax, "...");
7954 }
7955
7956 if (result == NULL) {
7957 // constructor calls
7958 JavaScriptFrameIterator it;
7959 JavaScriptFrame* frame = it.frame();
7960 if (frame->IsConstructor()) PrintF("new ");
7961 // function name
7962 Object* fun = frame->function();
7963 if (fun->IsJSFunction()) {
7964 PrintObject(JSFunction::cast(fun)->shared()->name());
7965 } else {
7966 PrintObject(fun);
7967 }
7968 // function arguments
7969 // (we are intentionally only printing the actually
7970 // supplied parameters, not all parameters required)
7971 PrintF("(this=");
7972 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007973 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 for (int i = 0; i < length; i++) {
7975 PrintF(", ");
7976 PrintObject(frame->GetParameter(i));
7977 }
7978 PrintF(") {\n");
7979
7980 } else {
7981 // function result
7982 PrintF("} -> ");
7983 PrintObject(result);
7984 PrintF("\n");
7985 }
7986}
7987
7988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007989RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007990 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007991 NoHandleAllocation ha;
7992 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007993 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007994}
7995
7996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007997RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998 NoHandleAllocation ha;
7999 PrintTransition(args[0]);
8000 return args[0]; // return TOS
8001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005 NoHandleAllocation ha;
8006 ASSERT(args.length() == 1);
8007
8008#ifdef DEBUG
8009 if (args[0]->IsString()) {
8010 // If we have a string, assume it's a code "marker"
8011 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008012 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008014 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8015 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008016 } else {
8017 PrintF("DebugPrint: ");
8018 }
8019 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008020 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008021 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008022 HeapObject::cast(args[0])->map()->Print();
8023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008025 // ShortPrint is available in release mode. Print is not.
8026 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027#endif
8028 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008029 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030
8031 return args[0]; // return TOS
8032}
8033
8034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008035RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008036 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008038 isolate->PrintStack();
8039 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040}
8041
8042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008043RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008044 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008045 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046
8047 // According to ECMA-262, section 15.9.1, page 117, the precision of
8048 // the number in a Date object representing a particular instant in
8049 // time is milliseconds. Therefore, we floor the result of getting
8050 // the OS time.
8051 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008052 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053}
8054
8055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008056RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008058 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008060 CONVERT_ARG_CHECKED(String, str, 0);
8061 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008062
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008063 CONVERT_ARG_CHECKED(JSArray, output, 1);
8064 RUNTIME_ASSERT(output->HasFastElements());
8065
8066 AssertNoAllocation no_allocation;
8067
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008068 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008069 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8070 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008071 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008072 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008073 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008074 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008075 result = DateParser::Parse(str->ToUC16Vector(), output_array);
8076 }
8077
8078 if (result) {
8079 return *output;
8080 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008082 }
8083}
8084
8085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008087 NoHandleAllocation ha;
8088 ASSERT(args.length() == 1);
8089
8090 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008091 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008092 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008093}
8094
8095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008096RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008098 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008100 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101}
8102
8103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008104RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105 NoHandleAllocation ha;
8106 ASSERT(args.length() == 1);
8107
8108 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008110}
8111
8112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008113RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008114 ASSERT(args.length() == 1);
8115 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008116 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008117 return JSGlobalObject::cast(global)->global_receiver();
8118}
8119
8120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008121RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008122 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008123 ASSERT_EQ(1, args.length());
8124 CONVERT_ARG_CHECKED(String, source, 0);
8125
8126 Handle<Object> result = JsonParser::Parse(source);
8127 if (result.is_null()) {
8128 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008129 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008130 return Failure::Exception();
8131 }
8132 return *result;
8133}
8134
8135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008136RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008137 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008138 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008139 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008140
ager@chromium.org381abbb2009-02-25 13:23:22 +00008141 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008142 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008143 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8144 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008145 true,
8146 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008147 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008148 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008149 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8150 context,
8151 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008152 return *fun;
8153}
8154
8155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008156static ObjectPair CompileGlobalEval(Isolate* isolate,
8157 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008158 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008159 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008160 // Deal with a normal eval call with a string argument. Compile it
8161 // and return the compiled function bound in the local context.
8162 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8163 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008164 Handle<Context>(isolate->context()),
8165 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008166 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008167 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008168 Handle<JSFunction> compiled =
8169 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8170 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008171 return MakePair(*compiled, *receiver);
8172}
8173
8174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008175RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008176 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008178 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008179 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008180 Handle<Object> receiver; // Will be overwritten.
8181
8182 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008183 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008184#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008185 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008186 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008187 StackFrameLocator locator;
8188 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008189 ASSERT(Context::cast(frame->context()) == *context);
8190#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008191
8192 // Find where the 'eval' symbol is bound. It is unaliased only if
8193 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008194 int index = -1;
8195 PropertyAttributes attributes = ABSENT;
8196 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008197 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8198 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008199 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008200 // Stop search when eval is found or when the global context is
8201 // reached.
8202 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008203 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204 context = Handle<Context>(Context::cast(context->closure()->context()),
8205 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008206 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008208 }
8209 }
8210
iposva@chromium.org245aa852009-02-10 00:49:54 +00008211 // If eval could not be resolved, it has been deleted and we need to
8212 // throw a reference error.
8213 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008214 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008215 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008216 isolate->factory()->NewReferenceError("not_defined",
8217 HandleVector(&name, 1));
8218 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008219 }
8220
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008221 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008222 // 'eval' is not bound in the global context. Just call the function
8223 // with the given arguments. This is not necessarily the global eval.
8224 if (receiver->IsContext()) {
8225 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008226 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008227 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 receiver = Handle<JSObject>(
8229 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008230 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008231 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008232 }
8233
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008234 // 'eval' is bound in the global context, but it may have been overwritten.
8235 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008237 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008238 return MakePair(*callee,
8239 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008240 }
8241
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008242 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 return CompileGlobalEval(isolate,
8244 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008245 args.at<Object>(2),
8246 static_cast<StrictModeFlag>(
8247 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008248}
8249
8250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008251RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008252 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008255 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008256
8257 // 'eval' is bound in the global context, but it may have been overwritten.
8258 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008260 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return MakePair(*callee,
8262 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008263 }
8264
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008265 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 return CompileGlobalEval(isolate,
8267 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008268 args.at<Object>(2),
8269 static_cast<StrictModeFlag>(
8270 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008271}
8272
8273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008274RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008275 // This utility adjusts the property attributes for newly created Function
8276 // object ("new Function(...)") by changing the map.
8277 // All it does is changing the prototype property to enumerable
8278 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008279 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008280 ASSERT(args.length() == 1);
8281 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282
8283 Handle<Map> map = func->shared()->strict_mode()
8284 ? isolate->strict_mode_function_instance_map()
8285 : isolate->function_instance_map();
8286
8287 ASSERT(func->map()->instance_type() == map->instance_type());
8288 ASSERT(func->map()->instance_size() == map->instance_size());
8289 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290 return *func;
8291}
8292
8293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008294RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008295 // Allocate a block of memory in NewSpace (filled with a filler).
8296 // Use as fallback for allocation in generated code when NewSpace
8297 // is full.
8298 ASSERT(args.length() == 1);
8299 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8300 int size = size_smi->value();
8301 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8302 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008303 Heap* heap = isolate->heap();
8304 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008305 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008306 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008308 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008310 }
8311 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008312 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008313}
8314
8315
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008316// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008317// array. Returns true if the element was pushed on the stack and
8318// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008319RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008320 ASSERT(args.length() == 2);
8321 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008322 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008323 RUNTIME_ASSERT(array->HasFastElements());
8324 int length = Smi::cast(array->length())->value();
8325 FixedArray* elements = FixedArray::cast(array->elements());
8326 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008327 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008328 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008329 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008330 // Strict not needed. Used for cycle detection in Array join implementation.
8331 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8332 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008333 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8334 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008335 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008336}
8337
8338
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008339/**
8340 * A simple visitor visits every element of Array's.
8341 * The backend storage can be a fixed array for fast elements case,
8342 * or a dictionary for sparse array. Since Dictionary is a subtype
8343 * of FixedArray, the class can be used by both fast and slow cases.
8344 * The second parameter of the constructor, fast_elements, specifies
8345 * whether the storage is a FixedArray or Dictionary.
8346 *
8347 * An index limit is used to deal with the situation that a result array
8348 * length overflows 32-bit non-negative integer.
8349 */
8350class ArrayConcatVisitor {
8351 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008352 ArrayConcatVisitor(Isolate* isolate,
8353 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008354 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008355 isolate_(isolate),
8356 storage_(Handle<FixedArray>::cast(
8357 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008358 index_offset_(0u),
8359 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008360
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008361 ~ArrayConcatVisitor() {
8362 clear_storage();
8363 }
8364
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008365 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008366 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008367 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008368
8369 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008370 if (index < static_cast<uint32_t>(storage_->length())) {
8371 storage_->set(index, *elm);
8372 return;
8373 }
8374 // Our initial estimate of length was foiled, possibly by
8375 // getters on the arrays increasing the length of later arrays
8376 // during iteration.
8377 // This shouldn't happen in anything but pathological cases.
8378 SetDictionaryMode(index);
8379 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008380 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008381 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008382 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008383 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008384 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008385 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008386 // Dictionary needed to grow.
8387 clear_storage();
8388 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008389 }
8390}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008391
8392 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008393 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8394 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008395 } else {
8396 index_offset_ += delta;
8397 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008398 }
8399
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008400 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008401 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008402 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008403 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008404 Handle<Map> map;
8405 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008406 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008407 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008408 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008409 }
8410 array->set_map(*map);
8411 array->set_length(*length);
8412 array->set_elements(*storage_);
8413 return array;
8414 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008415
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008416 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008417 // Convert storage to dictionary mode.
8418 void SetDictionaryMode(uint32_t index) {
8419 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008420 Handle<FixedArray> current_storage(*storage_);
8421 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008422 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008423 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8424 for (uint32_t i = 0; i < current_length; i++) {
8425 HandleScope loop_scope;
8426 Handle<Object> element(current_storage->get(i));
8427 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008428 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008430 if (!new_storage.is_identical_to(slow_storage)) {
8431 slow_storage = loop_scope.CloseAndEscape(new_storage);
8432 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008433 }
8434 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008435 clear_storage();
8436 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008437 fast_elements_ = false;
8438 }
8439
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008440 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008441 isolate_->global_handles()->Destroy(
8442 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008443 }
8444
8445 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008446 storage_ = Handle<FixedArray>::cast(
8447 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008448 }
8449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008451 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008452 // Index after last seen index. Always less than or equal to
8453 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008454 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008455 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008456};
8457
8458
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008459static uint32_t EstimateElementCount(Handle<JSArray> array) {
8460 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8461 int element_count = 0;
8462 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008463 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008464 // Fast elements can't have lengths that are not representable by
8465 // a 32-bit signed integer.
8466 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8467 int fast_length = static_cast<int>(length);
8468 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8469 for (int i = 0; i < fast_length; i++) {
8470 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008471 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008472 break;
8473 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008474 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008475 Handle<NumberDictionary> dictionary(
8476 NumberDictionary::cast(array->elements()));
8477 int capacity = dictionary->Capacity();
8478 for (int i = 0; i < capacity; i++) {
8479 Handle<Object> key(dictionary->KeyAt(i));
8480 if (dictionary->IsKey(*key)) {
8481 element_count++;
8482 }
8483 }
8484 break;
8485 }
8486 default:
8487 // External arrays are always dense.
8488 return length;
8489 }
8490 // As an estimate, we assume that the prototype doesn't contain any
8491 // inherited elements.
8492 return element_count;
8493}
8494
8495
8496
8497template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008498static void IterateExternalArrayElements(Isolate* isolate,
8499 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008500 bool elements_are_ints,
8501 bool elements_are_guaranteed_smis,
8502 ArrayConcatVisitor* visitor) {
8503 Handle<ExternalArrayClass> array(
8504 ExternalArrayClass::cast(receiver->elements()));
8505 uint32_t len = static_cast<uint32_t>(array->length());
8506
8507 ASSERT(visitor != NULL);
8508 if (elements_are_ints) {
8509 if (elements_are_guaranteed_smis) {
8510 for (uint32_t j = 0; j < len; j++) {
8511 HandleScope loop_scope;
8512 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8513 visitor->visit(j, e);
8514 }
8515 } else {
8516 for (uint32_t j = 0; j < len; j++) {
8517 HandleScope loop_scope;
8518 int64_t val = static_cast<int64_t>(array->get(j));
8519 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8520 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8521 visitor->visit(j, e);
8522 } else {
8523 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008524 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008525 visitor->visit(j, e);
8526 }
8527 }
8528 }
8529 } else {
8530 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008531 HandleScope loop_scope(isolate);
8532 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008533 visitor->visit(j, e);
8534 }
8535 }
8536}
8537
8538
8539// Used for sorting indices in a List<uint32_t>.
8540static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8541 uint32_t a = *ap;
8542 uint32_t b = *bp;
8543 return (a == b) ? 0 : (a < b) ? -1 : 1;
8544}
8545
8546
8547static void CollectElementIndices(Handle<JSObject> object,
8548 uint32_t range,
8549 List<uint32_t>* indices) {
8550 JSObject::ElementsKind kind = object->GetElementsKind();
8551 switch (kind) {
8552 case JSObject::FAST_ELEMENTS: {
8553 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8554 uint32_t length = static_cast<uint32_t>(elements->length());
8555 if (range < length) length = range;
8556 for (uint32_t i = 0; i < length; i++) {
8557 if (!elements->get(i)->IsTheHole()) {
8558 indices->Add(i);
8559 }
8560 }
8561 break;
8562 }
8563 case JSObject::DICTIONARY_ELEMENTS: {
8564 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008565 uint32_t capacity = dict->Capacity();
8566 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008567 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008568 Handle<Object> k(dict->KeyAt(j));
8569 if (dict->IsKey(*k)) {
8570 ASSERT(k->IsNumber());
8571 uint32_t index = static_cast<uint32_t>(k->Number());
8572 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008573 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008574 }
8575 }
8576 }
8577 break;
8578 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008579 default: {
8580 int dense_elements_length;
8581 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008582 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008583 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008584 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008585 break;
8586 }
8587 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8588 dense_elements_length =
8589 ExternalByteArray::cast(object->elements())->length();
8590 break;
8591 }
8592 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8593 dense_elements_length =
8594 ExternalUnsignedByteArray::cast(object->elements())->length();
8595 break;
8596 }
8597 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8598 dense_elements_length =
8599 ExternalShortArray::cast(object->elements())->length();
8600 break;
8601 }
8602 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8603 dense_elements_length =
8604 ExternalUnsignedShortArray::cast(object->elements())->length();
8605 break;
8606 }
8607 case JSObject::EXTERNAL_INT_ELEMENTS: {
8608 dense_elements_length =
8609 ExternalIntArray::cast(object->elements())->length();
8610 break;
8611 }
8612 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8613 dense_elements_length =
8614 ExternalUnsignedIntArray::cast(object->elements())->length();
8615 break;
8616 }
8617 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8618 dense_elements_length =
8619 ExternalFloatArray::cast(object->elements())->length();
8620 break;
8621 }
8622 default:
8623 UNREACHABLE();
8624 dense_elements_length = 0;
8625 break;
8626 }
8627 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8628 if (range <= length) {
8629 length = range;
8630 // We will add all indices, so we might as well clear it first
8631 // and avoid duplicates.
8632 indices->Clear();
8633 }
8634 for (uint32_t i = 0; i < length; i++) {
8635 indices->Add(i);
8636 }
8637 if (length == range) return; // All indices accounted for already.
8638 break;
8639 }
8640 }
8641
8642 Handle<Object> prototype(object->GetPrototype());
8643 if (prototype->IsJSObject()) {
8644 // The prototype will usually have no inherited element indices,
8645 // but we have to check.
8646 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8647 }
8648}
8649
8650
8651/**
8652 * A helper function that visits elements of a JSArray in numerical
8653 * order.
8654 *
8655 * The visitor argument called for each existing element in the array
8656 * with the element index and the element's value.
8657 * Afterwards it increments the base-index of the visitor by the array
8658 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008659 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008660 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008661static bool IterateElements(Isolate* isolate,
8662 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008663 ArrayConcatVisitor* visitor) {
8664 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8665 switch (receiver->GetElementsKind()) {
8666 case JSObject::FAST_ELEMENTS: {
8667 // Run through the elements FixedArray and use HasElement and GetElement
8668 // to check the prototype for missing elements.
8669 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8670 int fast_length = static_cast<int>(length);
8671 ASSERT(fast_length <= elements->length());
8672 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 HandleScope loop_scope(isolate);
8674 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008675 if (!element_value->IsTheHole()) {
8676 visitor->visit(j, element_value);
8677 } else if (receiver->HasElement(j)) {
8678 // Call GetElement on receiver, not its prototype, or getters won't
8679 // have the correct receiver.
8680 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008681 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008682 visitor->visit(j, element_value);
8683 }
8684 }
8685 break;
8686 }
8687 case JSObject::DICTIONARY_ELEMENTS: {
8688 Handle<NumberDictionary> dict(receiver->element_dictionary());
8689 List<uint32_t> indices(dict->Capacity() / 2);
8690 // Collect all indices in the object and the prototypes less
8691 // than length. This might introduce duplicates in the indices list.
8692 CollectElementIndices(receiver, length, &indices);
8693 indices.Sort(&compareUInt32);
8694 int j = 0;
8695 int n = indices.length();
8696 while (j < n) {
8697 HandleScope loop_scope;
8698 uint32_t index = indices[j];
8699 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008700 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008701 visitor->visit(index, element);
8702 // Skip to next different index (i.e., omit duplicates).
8703 do {
8704 j++;
8705 } while (j < n && indices[j] == index);
8706 }
8707 break;
8708 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008709 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8710 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8711 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008712 for (uint32_t j = 0; j < length; j++) {
8713 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8714 visitor->visit(j, e);
8715 }
8716 break;
8717 }
8718 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8719 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008720 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008721 break;
8722 }
8723 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8724 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008725 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008726 break;
8727 }
8728 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8729 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008730 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008731 break;
8732 }
8733 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8734 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008735 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008736 break;
8737 }
8738 case JSObject::EXTERNAL_INT_ELEMENTS: {
8739 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008740 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008741 break;
8742 }
8743 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8744 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008745 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008746 break;
8747 }
8748 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8749 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008750 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008751 break;
8752 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008753 default:
8754 UNREACHABLE();
8755 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008756 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008757 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008758 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008759}
8760
8761
8762/**
8763 * Array::concat implementation.
8764 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008765 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008766 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008767 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008768RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008769 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008770 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008771
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008772 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8773 int argument_count = static_cast<int>(arguments->length()->Number());
8774 RUNTIME_ASSERT(arguments->HasFastElements());
8775 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008776
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008777 // Pass 1: estimate the length and number of elements of the result.
8778 // The actual length can be larger if any of the arguments have getters
8779 // that mutate other arguments (but will otherwise be precise).
8780 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008781
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008782 uint32_t estimate_result_length = 0;
8783 uint32_t estimate_nof_elements = 0;
8784 {
8785 for (int i = 0; i < argument_count; i++) {
8786 HandleScope loop_scope;
8787 Handle<Object> obj(elements->get(i));
8788 uint32_t length_estimate;
8789 uint32_t element_estimate;
8790 if (obj->IsJSArray()) {
8791 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8792 length_estimate =
8793 static_cast<uint32_t>(array->length()->Number());
8794 element_estimate =
8795 EstimateElementCount(array);
8796 } else {
8797 length_estimate = 1;
8798 element_estimate = 1;
8799 }
8800 // Avoid overflows by capping at kMaxElementCount.
8801 if (JSObject::kMaxElementCount - estimate_result_length <
8802 length_estimate) {
8803 estimate_result_length = JSObject::kMaxElementCount;
8804 } else {
8805 estimate_result_length += length_estimate;
8806 }
8807 if (JSObject::kMaxElementCount - estimate_nof_elements <
8808 element_estimate) {
8809 estimate_nof_elements = JSObject::kMaxElementCount;
8810 } else {
8811 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008812 }
8813 }
8814 }
8815
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008816 // If estimated number of elements is more than half of length, a
8817 // fixed array (fast case) is more time and space-efficient than a
8818 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008819 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008820
8821 Handle<FixedArray> storage;
8822 if (fast_case) {
8823 // The backing storage array must have non-existing elements to
8824 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008825 storage = isolate->factory()->NewFixedArrayWithHoles(
8826 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008827 } else {
8828 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8829 uint32_t at_least_space_for = estimate_nof_elements +
8830 (estimate_nof_elements >> 2);
8831 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008832 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008833 }
8834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008836
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008837 for (int i = 0; i < argument_count; i++) {
8838 Handle<Object> obj(elements->get(i));
8839 if (obj->IsJSArray()) {
8840 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008841 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008842 return Failure::Exception();
8843 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008844 } else {
8845 visitor.visit(0, obj);
8846 visitor.increase_index_offset(1);
8847 }
8848 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008849
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008850 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008851}
8852
8853
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854// This will not allocate (flatten the string), but it may run
8855// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008856RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857 NoHandleAllocation ha;
8858 ASSERT(args.length() == 1);
8859
8860 CONVERT_CHECKED(String, string, args[0]);
8861 StringInputBuffer buffer(string);
8862 while (buffer.has_more()) {
8863 uint16_t character = buffer.GetNext();
8864 PrintF("%c", character);
8865 }
8866 return string;
8867}
8868
ager@chromium.org5ec48922009-05-05 07:25:34 +00008869// Moves all own elements of an object, that are below a limit, to positions
8870// starting at zero. All undefined values are placed after non-undefined values,
8871// and are followed by non-existing element. Does not change the length
8872// property.
8873// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008874RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008875 ASSERT(args.length() == 2);
8876 CONVERT_CHECKED(JSObject, object, args[0]);
8877 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8878 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879}
8880
8881
8882// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008883RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 ASSERT(args.length() == 2);
8885 CONVERT_CHECKED(JSArray, from, args[0]);
8886 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008887 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008888 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
8890 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008891 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008892 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008893 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008894 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008895 Object* new_map;
8896 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008897 to->set_map(Map::cast(new_map));
8898 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008900 Object* obj;
8901 { MaybeObject* maybe_obj = from->ResetElements();
8902 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8903 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008904 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905 return to;
8906}
8907
8908
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008909// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008910RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008911 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008912 CONVERT_CHECKED(JSObject, object, args[0]);
8913 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008915 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008916 } else if (object->IsJSArray()) {
8917 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008919 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008920 }
8921}
8922
8923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008924RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008926
8927 ASSERT_EQ(3, args.length());
8928
ager@chromium.orgac091b72010-05-05 07:34:42 +00008929 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008930 Handle<Object> key1 = args.at<Object>(1);
8931 Handle<Object> key2 = args.at<Object>(2);
8932
8933 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008934 if (!key1->ToArrayIndex(&index1)
8935 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008936 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008937 }
8938
ager@chromium.orgac091b72010-05-05 07:34:42 +00008939 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8940 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008942 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008943 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008945 RETURN_IF_EMPTY_HANDLE(isolate,
8946 SetElement(jsobject, index1, tmp2, kStrictMode));
8947 RETURN_IF_EMPTY_HANDLE(isolate,
8948 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008950 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008951}
8952
8953
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008954// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008955// might have elements. Can either return keys (positive integers) or
8956// intervals (pair of a negative integer (-start-1) followed by a
8957// positive (length)) or undefined values.
8958// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008959RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008961 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00008962 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008963 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008964 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 // Create an array and get all the keys into it, then remove all the
8966 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008967 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008968 int keys_length = keys->length();
8969 for (int i = 0; i < keys_length; i++) {
8970 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008971 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008972 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 // Zap invalid keys.
8974 keys->set_undefined(i);
8975 }
8976 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008979 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008980 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008982 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008983 uint32_t actual_length =
8984 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008985 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008987 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008989 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 }
8991}
8992
8993
8994// DefineAccessor takes an optional final argument which is the
8995// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8996// to the way accessors are implemented, it is set for both the getter
8997// and setter on the first call to DefineAccessor and ignored on
8998// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008999RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9001 // Compute attributes.
9002 PropertyAttributes attributes = NONE;
9003 if (args.length() == 5) {
9004 CONVERT_CHECKED(Smi, attrs, args[4]);
9005 int value = attrs->value();
9006 // Only attribute bits should be set.
9007 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9008 attributes = static_cast<PropertyAttributes>(value);
9009 }
9010
9011 CONVERT_CHECKED(JSObject, obj, args[0]);
9012 CONVERT_CHECKED(String, name, args[1]);
9013 CONVERT_CHECKED(Smi, flag, args[2]);
9014 CONVERT_CHECKED(JSFunction, fun, args[3]);
9015 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9016}
9017
9018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009019RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020 ASSERT(args.length() == 3);
9021 CONVERT_CHECKED(JSObject, obj, args[0]);
9022 CONVERT_CHECKED(String, name, args[1]);
9023 CONVERT_CHECKED(Smi, flag, args[2]);
9024 return obj->LookupAccessor(name, flag->value() == 0);
9025}
9026
9027
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009028#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009029RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009030 ASSERT(args.length() == 0);
9031 return Execution::DebugBreakHelper();
9032}
9033
9034
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035// Helper functions for wrapping and unwrapping stack frame ids.
9036static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009037 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038 return Smi::FromInt(id >> 2);
9039}
9040
9041
9042static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9043 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9044}
9045
9046
9047// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009048// args[0]: debug event listener function to set or null or undefined for
9049// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009051RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009053 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9054 args[0]->IsUndefined() ||
9055 args[0]->IsNull());
9056 Handle<Object> callback = args.at<Object>(0);
9057 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009060 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061}
9062
9063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009064RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009065 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 isolate->stack_guard()->DebugBreak();
9067 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068}
9069
9070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009071static MaybeObject* DebugLookupResultValue(Heap* heap,
9072 Object* receiver,
9073 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009074 LookupResult* result,
9075 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009076 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009078 case NORMAL:
9079 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009080 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082 }
9083 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009084 case FIELD:
9085 value =
9086 JSObject::cast(
9087 result->holder())->FastPropertyAt(result->GetFieldIndex());
9088 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009089 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009090 }
9091 return value;
9092 case CONSTANT_FUNCTION:
9093 return result->GetConstantFunction();
9094 case CALLBACKS: {
9095 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009096 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009097 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009098 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009099 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009100 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009101 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 maybe_value = heap->isolate()->pending_exception();
9103 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009104 if (caught_exception != NULL) {
9105 *caught_exception = true;
9106 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009107 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009108 }
9109 return value;
9110 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009112 }
9113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009115 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009116 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009117 case CONSTANT_TRANSITION:
9118 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009119 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009120 default:
9121 UNREACHABLE();
9122 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009123 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009124 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009125}
9126
9127
ager@chromium.org32912102009-01-16 10:38:43 +00009128// Get debugger related details for an object property.
9129// args[0]: object holding property
9130// args[1]: name of the property
9131//
9132// The array returned contains the following information:
9133// 0: Property value
9134// 1: Property details
9135// 2: Property value is exception
9136// 3: Getter function if defined
9137// 4: Setter function if defined
9138// Items 2-4 are only filled if the property has either a getter or a setter
9139// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009140RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142
9143 ASSERT(args.length() == 2);
9144
9145 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9146 CONVERT_ARG_CHECKED(String, name, 1);
9147
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009148 // Make sure to set the current context to the context before the debugger was
9149 // entered (if the debugger is entered). The reason for switching context here
9150 // is that for some property lookups (accessors and interceptors) callbacks
9151 // into the embedding application can occour, and the embedding application
9152 // could have the assumption that its own global context is the current
9153 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009154 SaveContext save(isolate);
9155 if (isolate->debug()->InDebugger()) {
9156 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009157 }
9158
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009159 // Skip the global proxy as it has no properties and always delegates to the
9160 // real global object.
9161 if (obj->IsJSGlobalProxy()) {
9162 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9163 }
9164
9165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 // Check if the name is trivially convertible to an index and get the element
9167 // if so.
9168 uint32_t index;
9169 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009171 Object* element_or_char;
9172 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009173 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009174 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9175 return maybe_element_or_char;
9176 }
9177 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009178 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009180 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009181 }
9182
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009183 // Find the number of objects making up this.
9184 int length = LocalPrototypeChainLength(*obj);
9185
9186 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009187 Handle<JSObject> jsproto = obj;
9188 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009189 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009190 jsproto->LocalLookup(*name, &result);
9191 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009192 // LookupResult is not GC safe as it holds raw object pointers.
9193 // GC can happen later in this code so put the required fields into
9194 // local variables using handles when required for later use.
9195 PropertyType result_type = result.type();
9196 Handle<Object> result_callback_obj;
9197 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009198 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9199 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009200 }
9201 Smi* property_details = result.GetPropertyDetails().AsSmi();
9202 // DebugLookupResultValue can cause GC so details from LookupResult needs
9203 // to be copied to handles before this.
9204 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009205 Object* raw_value;
9206 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 DebugLookupResultValue(isolate->heap(), *obj, *name,
9208 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009209 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9210 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009211 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009212
9213 // If the callback object is a fixed array then it contains JavaScript
9214 // getter and/or setter.
9215 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9216 result_callback_obj->IsFixedArray();
9217 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009218 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009219 details->set(0, *value);
9220 details->set(1, property_details);
9221 if (hasJavaScriptAccessors) {
9222 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 caught_exception ? isolate->heap()->true_value()
9224 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009225 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9226 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9227 }
9228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009229 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009230 }
9231 if (i < length - 1) {
9232 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9233 }
9234 }
9235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237}
9238
9239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009240RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009242
9243 ASSERT(args.length() == 2);
9244
9245 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9246 CONVERT_ARG_CHECKED(String, name, 1);
9247
9248 LookupResult result;
9249 obj->Lookup(*name, &result);
9250 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009253 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009254}
9255
9256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257// Return the property type calculated from the property details.
9258// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009259RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260 ASSERT(args.length() == 1);
9261 CONVERT_CHECKED(Smi, details, args[0]);
9262 PropertyType type = PropertyDetails(details).type();
9263 return Smi::FromInt(static_cast<int>(type));
9264}
9265
9266
9267// Return the property attribute calculated from the property details.
9268// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009269RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270 ASSERT(args.length() == 1);
9271 CONVERT_CHECKED(Smi, details, args[0]);
9272 PropertyAttributes attributes = PropertyDetails(details).attributes();
9273 return Smi::FromInt(static_cast<int>(attributes));
9274}
9275
9276
9277// Return the property insertion index calculated from the property details.
9278// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009279RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280 ASSERT(args.length() == 1);
9281 CONVERT_CHECKED(Smi, details, args[0]);
9282 int index = PropertyDetails(details).index();
9283 return Smi::FromInt(index);
9284}
9285
9286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287// Return property value from named interceptor.
9288// args[0]: object
9289// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009290RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009292 ASSERT(args.length() == 2);
9293 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9294 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9295 CONVERT_ARG_CHECKED(String, name, 1);
9296
9297 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009298 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299}
9300
9301
9302// Return element value from indexed interceptor.
9303// args[0]: object
9304// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009305RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009306 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307 ASSERT(args.length() == 2);
9308 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9309 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9310 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9311
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009312 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313}
9314
9315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009316RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009317 ASSERT(args.length() >= 1);
9318 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009319 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009320 if (isolate->debug()->break_id() == 0 ||
9321 break_id != isolate->debug()->break_id()) {
9322 return isolate->Throw(
9323 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324 }
9325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009326 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009327}
9328
9329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009330RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009331 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 ASSERT(args.length() == 1);
9333
9334 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009335 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009336 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9337 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009338 if (!maybe_result->ToObject(&result)) return maybe_result;
9339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340
9341 // Count all frames which are relevant to debugging stack trace.
9342 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009344 if (id == StackFrame::NO_ID) {
9345 // If there is no JavaScript stack frame count is 0.
9346 return Smi::FromInt(0);
9347 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009348 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 return Smi::FromInt(n);
9350}
9351
9352
9353static const int kFrameDetailsFrameIdIndex = 0;
9354static const int kFrameDetailsReceiverIndex = 1;
9355static const int kFrameDetailsFunctionIndex = 2;
9356static const int kFrameDetailsArgumentCountIndex = 3;
9357static const int kFrameDetailsLocalCountIndex = 4;
9358static const int kFrameDetailsSourcePositionIndex = 5;
9359static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009360static const int kFrameDetailsAtReturnIndex = 7;
9361static const int kFrameDetailsDebuggerFrameIndex = 8;
9362static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363
9364// Return an array with frame details
9365// args[0]: number: break id
9366// args[1]: number: frame index
9367//
9368// The array returned contains the following information:
9369// 0: Frame id
9370// 1: Receiver
9371// 2: Function
9372// 3: Argument count
9373// 4: Local count
9374// 5: Source position
9375// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009376// 7: Is at return
9377// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378// Arguments name, value
9379// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009380// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009382 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009383 ASSERT(args.length() == 2);
9384
9385 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009386 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009387 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9388 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009389 if (!maybe_check->ToObject(&check)) return maybe_check;
9390 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393
9394 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009396 if (id == StackFrame::NO_ID) {
9397 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009399 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009400 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009401 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009402 for (; !it.done(); it.Advance()) {
9403 if (count == index) break;
9404 count++;
9405 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009408 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009409 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411 // Traverse the saved contexts chain to find the active context for the
9412 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009413 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009414 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009415 save = save->prev();
9416 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009417 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418
9419 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009420 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421
9422 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009423 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009424 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425
9426 // Check for constructor frame.
9427 bool constructor = it.frame()->IsConstructor();
9428
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009429 // Get scope info and read from it for local variable information.
9430 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009431 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009432 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433
9434 // Get the context.
9435 Handle<Context> context(Context::cast(it.frame()->context()));
9436
9437 // Get the locals names and values into a temporary array.
9438 //
9439 // TODO(1240907): Hide compiler-introduced stack variables
9440 // (e.g. .result)? For users of the debugger, they will probably be
9441 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009442 Handle<FixedArray> locals =
9443 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009445 // Fill in the names of the locals.
9446 for (int i = 0; i < info.NumberOfLocals(); i++) {
9447 locals->set(i * 2, *info.LocalName(i));
9448 }
9449
9450 // Fill in the values of the locals.
9451 for (int i = 0; i < info.NumberOfLocals(); i++) {
9452 if (is_optimized_frame) {
9453 // If we are inspecting an optimized frame use undefined as the
9454 // value for all locals.
9455 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009456 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009457 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009459 } else if (i < info.number_of_stack_slots()) {
9460 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009461 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9462 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009463 // Traverse the context chain to the function context as all local
9464 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009465 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009466 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009467 context = Handle<Context>(context->previous());
9468 }
9469 ASSERT(context->is_function_context());
9470 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009471 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472 }
9473 }
9474
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009475 // Check whether this frame is positioned at return. If not top
9476 // frame or if the frame is optimized it cannot be at a return.
9477 bool at_return = false;
9478 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009480 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009481
9482 // If positioned just before return find the value to be returned and add it
9483 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009485 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009486 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009487 Address internal_frame_sp = NULL;
9488 while (!it2.done()) {
9489 if (it2.frame()->is_internal()) {
9490 internal_frame_sp = it2.frame()->sp();
9491 } else {
9492 if (it2.frame()->is_java_script()) {
9493 if (it2.frame()->id() == it.frame()->id()) {
9494 // The internal frame just before the JavaScript frame contains the
9495 // value to return on top. A debug break at return will create an
9496 // internal frame to store the return value (eax/rax/r0) before
9497 // entering the debug break exit frame.
9498 if (internal_frame_sp != NULL) {
9499 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 Handle<Object>(Memory::Object_at(internal_frame_sp),
9501 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009502 break;
9503 }
9504 }
9505 }
9506
9507 // Indicate that the previous frame was not an internal frame.
9508 internal_frame_sp = NULL;
9509 }
9510 it2.Advance();
9511 }
9512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513
9514 // Now advance to the arguments adapter frame (if any). It contains all
9515 // the provided parameters whereas the function frame always have the number
9516 // of arguments matching the functions parameters. The rest of the
9517 // information (except for what is collected above) is the same.
9518 it.AdvanceToArgumentsFrame();
9519
9520 // Find the number of arguments to fill. At least fill the number of
9521 // parameters for the function and fill more if more parameters are provided.
9522 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009523 if (argument_count < it.frame()->ComputeParametersCount()) {
9524 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 }
9526
9527 // Calculate the size of the result.
9528 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009529 2 * (argument_count + info.NumberOfLocals()) +
9530 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009531 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009532
9533 // Add the frame id.
9534 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9535
9536 // Add the function (same as in function frame).
9537 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9538
9539 // Add the arguments count.
9540 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9541
9542 // Add the locals count
9543 details->set(kFrameDetailsLocalCountIndex,
9544 Smi::FromInt(info.NumberOfLocals()));
9545
9546 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009547 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9549 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009550 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009551 }
9552
9553 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009556 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009559 // Add information on whether this frame is invoked in the debugger context.
9560 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009561 heap->ToBoolean(*save->context() ==
9562 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009563
9564 // Fill the dynamic part.
9565 int details_index = kFrameDetailsFirstDynamicIndex;
9566
9567 // Add arguments name and value.
9568 for (int i = 0; i < argument_count; i++) {
9569 // Name of the argument.
9570 if (i < info.number_of_parameters()) {
9571 details->set(details_index++, *info.parameter_name(i));
9572 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009574 }
9575
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009576 // Parameter value. If we are inspecting an optimized frame, use
9577 // undefined as the value.
9578 //
9579 // TODO(3141533): We should be able to get the actual parameter
9580 // value for optimized frames.
9581 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009582 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009583 details->set(details_index++, it.frame()->GetParameter(i));
9584 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009585 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586 }
9587 }
9588
9589 // Add locals name and value from the temporary copy from the function frame.
9590 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9591 details->set(details_index++, locals->get(i));
9592 }
9593
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009594 // Add the value being returned.
9595 if (at_return) {
9596 details->set(details_index++, *return_value);
9597 }
9598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009599 // Add the receiver (same as in function frame).
9600 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9601 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009602 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009603 if (!receiver->IsJSObject()) {
9604 // If the receiver is NOT a JSObject we have hit an optimization
9605 // where a value object is not converted into a wrapped JS objects.
9606 // To hide this optimization from the debugger, we wrap the receiver
9607 // by creating correct wrapper object based on the calling frame's
9608 // global context.
9609 it.Advance();
9610 Handle<Context> calling_frames_global_context(
9611 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009612 receiver =
9613 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 }
9615 details->set(kFrameDetailsReceiverIndex, *receiver);
9616
9617 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009619}
9620
9621
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009622// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009623static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009624 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009625 Handle<SerializedScopeInfo> serialized_scope_info,
9626 ScopeInfo<>& scope_info,
9627 Handle<Context> context,
9628 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009629 // Fill all context locals to the context extension.
9630 for (int i = Context::MIN_CONTEXT_SLOTS;
9631 i < scope_info.number_of_context_slots();
9632 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009633 int context_index = serialized_scope_info->ContextSlotIndex(
9634 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009635
9636 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009637 if (*scope_info.context_slot_name(i) !=
9638 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009639 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009641 SetProperty(scope_object,
9642 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009643 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009644 NONE,
9645 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009646 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009647 }
9648 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009649
9650 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009651}
9652
9653
9654// Create a plain JSObject which materializes the local scope for the specified
9655// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009656static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9657 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009658 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009659 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009660 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9661 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009662
9663 // Allocate and initialize a JSObject with all the arguments, stack locals
9664 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009665 Handle<JSObject> local_scope =
9666 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009667
9668 // First fill all parameters.
9669 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009670 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009671 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009672 SetProperty(local_scope,
9673 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009674 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009675 NONE,
9676 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009677 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009678 }
9679
9680 // Second fill all stack locals.
9681 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009682 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009683 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009684 SetProperty(local_scope,
9685 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009686 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009687 NONE,
9688 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009689 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009690 }
9691
9692 // Third fill all context locals.
9693 Handle<Context> frame_context(Context::cast(frame->context()));
9694 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009695 if (!CopyContextLocalsToScopeObject(isolate,
9696 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009697 function_context, local_scope)) {
9698 return Handle<JSObject>();
9699 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009700
9701 // Finally copy any properties from the function context extension. This will
9702 // be variables introduced by eval.
9703 if (function_context->closure() == *function) {
9704 if (function_context->has_extension() &&
9705 !function_context->IsGlobalContext()) {
9706 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009707 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009708 for (int i = 0; i < keys->length(); i++) {
9709 // Names of variables introduced by eval are strings.
9710 ASSERT(keys->get(i)->IsString());
9711 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009712 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009713 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009714 SetProperty(local_scope,
9715 key,
9716 GetProperty(ext, key),
9717 NONE,
9718 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009719 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009720 }
9721 }
9722 }
9723 return local_scope;
9724}
9725
9726
9727// Create a plain JSObject which materializes the closure content for the
9728// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9730 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009731 ASSERT(context->is_function_context());
9732
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009733 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009734 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9735 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009736
9737 // Allocate and initialize a JSObject with all the content of theis function
9738 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 Handle<JSObject> closure_scope =
9740 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009741
9742 // Check whether the arguments shadow object exists.
9743 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009744 shared->scope_info()->ContextSlotIndex(
9745 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009746 if (arguments_shadow_index >= 0) {
9747 // In this case all the arguments are available in the arguments shadow
9748 // object.
9749 Handle<JSObject> arguments_shadow(
9750 JSObject::cast(context->get(arguments_shadow_index)));
9751 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009752 // We don't expect exception-throwing getters on the arguments shadow.
9753 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009754 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009755 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009756 SetProperty(closure_scope,
9757 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009759 NONE,
9760 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009761 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009762 }
9763 }
9764
9765 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 if (!CopyContextLocalsToScopeObject(isolate,
9767 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009768 context, closure_scope)) {
9769 return Handle<JSObject>();
9770 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009771
9772 // Finally copy any properties from the function context extension. This will
9773 // be variables introduced by eval.
9774 if (context->has_extension()) {
9775 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009776 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009777 for (int i = 0; i < keys->length(); i++) {
9778 // Names of variables introduced by eval are strings.
9779 ASSERT(keys->get(i)->IsString());
9780 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009781 RETURN_IF_EMPTY_HANDLE_VALUE(
9782 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009783 SetProperty(closure_scope,
9784 key,
9785 GetProperty(ext, key),
9786 NONE,
9787 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009788 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009789 }
9790 }
9791
9792 return closure_scope;
9793}
9794
9795
9796// Iterate over the actual scopes visible from a stack frame. All scopes are
9797// backed by an actual context except the local scope, which is inserted
9798// "artifically" in the context chain.
9799class ScopeIterator {
9800 public:
9801 enum ScopeType {
9802 ScopeTypeGlobal = 0,
9803 ScopeTypeLocal,
9804 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009805 ScopeTypeClosure,
9806 // Every catch block contains an implicit with block (its parameter is
9807 // a JSContextExtensionObject) that extends current scope with a variable
9808 // holding exception object. Such with blocks are treated as scopes of their
9809 // own type.
9810 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009811 };
9812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009813 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9814 : isolate_(isolate),
9815 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009816 function_(JSFunction::cast(frame->function())),
9817 context_(Context::cast(frame->context())),
9818 local_done_(false),
9819 at_local_(false) {
9820
9821 // Check whether the first scope is actually a local scope.
9822 if (context_->IsGlobalContext()) {
9823 // If there is a stack slot for .result then this local scope has been
9824 // created for evaluating top level code and it is not a real local scope.
9825 // Checking for the existence of .result seems fragile, but the scope info
9826 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009827 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009828 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009829 at_local_ = index < 0;
9830 } else if (context_->is_function_context()) {
9831 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009832 } else if (context_->closure() != *function_) {
9833 // The context_ is a with block from the outer function.
9834 ASSERT(context_->has_extension());
9835 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009836 }
9837 }
9838
9839 // More scopes?
9840 bool Done() { return context_.is_null(); }
9841
9842 // Move to the next scope.
9843 void Next() {
9844 // If at a local scope mark the local scope as passed.
9845 if (at_local_) {
9846 at_local_ = false;
9847 local_done_ = true;
9848
9849 // If the current context is not associated with the local scope the
9850 // current context is the next real scope, so don't move to the next
9851 // context in this case.
9852 if (context_->closure() != *function_) {
9853 return;
9854 }
9855 }
9856
9857 // The global scope is always the last in the chain.
9858 if (context_->IsGlobalContext()) {
9859 context_ = Handle<Context>();
9860 return;
9861 }
9862
9863 // Move to the next context.
9864 if (context_->is_function_context()) {
9865 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9866 } else {
9867 context_ = Handle<Context>(context_->previous());
9868 }
9869
9870 // If passing the local scope indicate that the current scope is now the
9871 // local scope.
9872 if (!local_done_ &&
9873 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9874 at_local_ = true;
9875 }
9876 }
9877
9878 // Return the type of the current scope.
9879 int Type() {
9880 if (at_local_) {
9881 return ScopeTypeLocal;
9882 }
9883 if (context_->IsGlobalContext()) {
9884 ASSERT(context_->global()->IsGlobalObject());
9885 return ScopeTypeGlobal;
9886 }
9887 if (context_->is_function_context()) {
9888 return ScopeTypeClosure;
9889 }
9890 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009891 // Current scope is either an explicit with statement or a with statement
9892 // implicitely generated for a catch block.
9893 // If the extension object here is a JSContextExtensionObject then
9894 // current with statement is one frome a catch block otherwise it's a
9895 // regular with statement.
9896 if (context_->extension()->IsJSContextExtensionObject()) {
9897 return ScopeTypeCatch;
9898 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009899 return ScopeTypeWith;
9900 }
9901
9902 // Return the JavaScript object with the content of the current scope.
9903 Handle<JSObject> ScopeObject() {
9904 switch (Type()) {
9905 case ScopeIterator::ScopeTypeGlobal:
9906 return Handle<JSObject>(CurrentContext()->global());
9907 break;
9908 case ScopeIterator::ScopeTypeLocal:
9909 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009910 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009911 break;
9912 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009913 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009914 // Return the with object.
9915 return Handle<JSObject>(CurrentContext()->extension());
9916 break;
9917 case ScopeIterator::ScopeTypeClosure:
9918 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009920 break;
9921 }
9922 UNREACHABLE();
9923 return Handle<JSObject>();
9924 }
9925
9926 // Return the context for this scope. For the local context there might not
9927 // be an actual context.
9928 Handle<Context> CurrentContext() {
9929 if (at_local_ && context_->closure() != *function_) {
9930 return Handle<Context>();
9931 }
9932 return context_;
9933 }
9934
9935#ifdef DEBUG
9936 // Debug print of the content of the current scope.
9937 void DebugPrint() {
9938 switch (Type()) {
9939 case ScopeIterator::ScopeTypeGlobal:
9940 PrintF("Global:\n");
9941 CurrentContext()->Print();
9942 break;
9943
9944 case ScopeIterator::ScopeTypeLocal: {
9945 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009946 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009947 scope_info.Print();
9948 if (!CurrentContext().is_null()) {
9949 CurrentContext()->Print();
9950 if (CurrentContext()->has_extension()) {
9951 Handle<JSObject> extension =
9952 Handle<JSObject>(CurrentContext()->extension());
9953 if (extension->IsJSContextExtensionObject()) {
9954 extension->Print();
9955 }
9956 }
9957 }
9958 break;
9959 }
9960
9961 case ScopeIterator::ScopeTypeWith: {
9962 PrintF("With:\n");
9963 Handle<JSObject> extension =
9964 Handle<JSObject>(CurrentContext()->extension());
9965 extension->Print();
9966 break;
9967 }
9968
ager@chromium.orga1645e22009-09-09 19:27:10 +00009969 case ScopeIterator::ScopeTypeCatch: {
9970 PrintF("Catch:\n");
9971 Handle<JSObject> extension =
9972 Handle<JSObject>(CurrentContext()->extension());
9973 extension->Print();
9974 break;
9975 }
9976
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009977 case ScopeIterator::ScopeTypeClosure: {
9978 PrintF("Closure:\n");
9979 CurrentContext()->Print();
9980 if (CurrentContext()->has_extension()) {
9981 Handle<JSObject> extension =
9982 Handle<JSObject>(CurrentContext()->extension());
9983 if (extension->IsJSContextExtensionObject()) {
9984 extension->Print();
9985 }
9986 }
9987 break;
9988 }
9989
9990 default:
9991 UNREACHABLE();
9992 }
9993 PrintF("\n");
9994 }
9995#endif
9996
9997 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009999 JavaScriptFrame* frame_;
10000 Handle<JSFunction> function_;
10001 Handle<Context> context_;
10002 bool local_done_;
10003 bool at_local_;
10004
10005 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10006};
10007
10008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010011 ASSERT(args.length() == 2);
10012
10013 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010014 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010015 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10016 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010017 if (!maybe_check->ToObject(&check)) return maybe_check;
10018 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010019 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10020
10021 // Get the frame where the debugging is performed.
10022 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010023 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010024 JavaScriptFrame* frame = it.frame();
10025
10026 // Count the visible scopes.
10027 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010028 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010029 n++;
10030 }
10031
10032 return Smi::FromInt(n);
10033}
10034
10035
10036static const int kScopeDetailsTypeIndex = 0;
10037static const int kScopeDetailsObjectIndex = 1;
10038static const int kScopeDetailsSize = 2;
10039
10040// Return an array with scope details
10041// args[0]: number: break id
10042// args[1]: number: frame index
10043// args[2]: number: scope index
10044//
10045// The array returned contains the following information:
10046// 0: Scope type
10047// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010048RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010049 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010050 ASSERT(args.length() == 3);
10051
10052 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010053 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010054 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10055 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010056 if (!maybe_check->ToObject(&check)) return maybe_check;
10057 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010058 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10059 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10060
10061 // Get the frame where the debugging is performed.
10062 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010063 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010064 JavaScriptFrame* frame = frame_it.frame();
10065
10066 // Find the requested scope.
10067 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010068 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010069 for (; !it.Done() && n < index; it.Next()) {
10070 n++;
10071 }
10072 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010074 }
10075
10076 // Calculate the size of the result.
10077 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010079
10080 // Fill in scope details.
10081 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010082 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010084 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010085
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010086 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010087}
10088
10089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010090RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010092 ASSERT(args.length() == 0);
10093
10094#ifdef DEBUG
10095 // Print the scopes for the top frame.
10096 StackFrameLocator locator;
10097 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010098 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010099 it.DebugPrint();
10100 }
10101#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010103}
10104
10105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010106RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010108 ASSERT(args.length() == 1);
10109
10110 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010111 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010112 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10113 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010114 if (!maybe_result->ToObject(&result)) return maybe_result;
10115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010116
10117 // Count all archived V8 threads.
10118 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010119 for (ThreadState* thread =
10120 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010121 thread != NULL;
10122 thread = thread->Next()) {
10123 n++;
10124 }
10125
10126 // Total number of threads is current thread and archived threads.
10127 return Smi::FromInt(n + 1);
10128}
10129
10130
10131static const int kThreadDetailsCurrentThreadIndex = 0;
10132static const int kThreadDetailsThreadIdIndex = 1;
10133static const int kThreadDetailsSize = 2;
10134
10135// Return an array with thread details
10136// args[0]: number: break id
10137// args[1]: number: thread index
10138//
10139// The array returned contains the following information:
10140// 0: Is current thread?
10141// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010142RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010144 ASSERT(args.length() == 2);
10145
10146 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010147 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010148 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10149 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010150 if (!maybe_check->ToObject(&check)) return maybe_check;
10151 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010152 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10153
10154 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 Handle<FixedArray> details =
10156 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010157
10158 // Thread index 0 is current thread.
10159 if (index == 0) {
10160 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 details->set(kThreadDetailsCurrentThreadIndex,
10162 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010163 details->set(kThreadDetailsThreadIdIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 Smi::FromInt(
10165 isolate->thread_manager()->CurrentId()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010166 } else {
10167 // Find the thread with the requested index.
10168 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010169 ThreadState* thread =
10170 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010171 while (index != n && thread != NULL) {
10172 thread = thread->Next();
10173 n++;
10174 }
10175 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010177 }
10178
10179 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010180 details->set(kThreadDetailsCurrentThreadIndex,
10181 isolate->heap()->false_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010182 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
10183 }
10184
10185 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010186 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010187}
10188
10189
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010190// Sets the disable break state
10191// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010192RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010194 ASSERT(args.length() == 1);
10195 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 isolate->debug()->set_disable_break(disable_break);
10197 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010198}
10199
10200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010201RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 ASSERT(args.length() == 1);
10204
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010205 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10206 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207 // Find the number of break points
10208 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010210 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010211 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010212 Handle<FixedArray>::cast(break_locations));
10213}
10214
10215
10216// Set a break point in a function
10217// args[0]: function
10218// args[1]: number: break source position (within the function source)
10219// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010220RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010221 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010223 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10224 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10226 RUNTIME_ASSERT(source_position >= 0);
10227 Handle<Object> break_point_object_arg = args.at<Object>(2);
10228
10229 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10231 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010233 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234}
10235
10236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010237Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10238 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010239 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 // Iterate the heap looking for SharedFunctionInfo generated from the
10241 // script. The inner most SharedFunctionInfo containing the source position
10242 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010243 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 // which is found is not compiled it is compiled and the heap is iterated
10245 // again as the compilation might create inner functions from the newly
10246 // compiled function and the actual requested break point might be in one of
10247 // these functions.
10248 bool done = false;
10249 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010250 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252 while (!done) {
10253 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010254 for (HeapObject* obj = iterator.next();
10255 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 if (obj->IsSharedFunctionInfo()) {
10257 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10258 if (shared->script() == *script) {
10259 // If the SharedFunctionInfo found has the requested script data and
10260 // contains the source position it is a candidate.
10261 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010262 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 start_position = shared->start_position();
10264 }
10265 if (start_position <= position &&
10266 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010267 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010268 // candidate this is the new candidate.
10269 if (target.is_null()) {
10270 target_start_position = start_position;
10271 target = shared;
10272 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010273 if (target_start_position == start_position &&
10274 shared->end_position() == target->end_position()) {
10275 // If a top-level function contain only one function
10276 // declartion the source for the top-level and the function is
10277 // the same. In that case prefer the non top-level function.
10278 if (!shared->is_toplevel()) {
10279 target_start_position = start_position;
10280 target = shared;
10281 }
10282 } else if (target_start_position <= start_position &&
10283 shared->end_position() <= target->end_position()) {
10284 // This containment check includes equality as a function inside
10285 // a top-level function can share either start or end position
10286 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287 target_start_position = start_position;
10288 target = shared;
10289 }
10290 }
10291 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 }
10293 }
10294 }
10295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010297 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 }
10299
10300 // If the candidate found is compiled we are done. NOTE: when lazy
10301 // compilation of inner functions is introduced some additional checking
10302 // needs to be done here to compile inner functions.
10303 done = target->is_compiled();
10304 if (!done) {
10305 // If the candidate is not compiled compile it to reveal any inner
10306 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010307 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 }
10309 }
10310
10311 return *target;
10312}
10313
10314
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010315// Changes the state of a break point in a script and returns source position
10316// where break point was set. NOTE: Regarding performance see the NOTE for
10317// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318// args[0]: script to set break point in
10319// args[1]: number: break source position (within the script source)
10320// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010321RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 ASSERT(args.length() == 3);
10324 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10325 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10326 RUNTIME_ASSERT(source_position >= 0);
10327 Handle<Object> break_point_object_arg = args.at<Object>(2);
10328
10329 // Get the script from the script wrapper.
10330 RUNTIME_ASSERT(wrapper->value()->IsScript());
10331 Handle<Script> script(Script::cast(wrapper->value()));
10332
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010333 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 if (!result->IsUndefined()) {
10336 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10337 // Find position within function. The script position might be before the
10338 // source position of the first function.
10339 int position;
10340 if (shared->start_position() > source_position) {
10341 position = 0;
10342 } else {
10343 position = source_position - shared->start_position();
10344 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010346 position += shared->start_position();
10347 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350}
10351
10352
10353// Clear a break point
10354// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010355RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010356 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357 ASSERT(args.length() == 1);
10358 Handle<Object> break_point_object_arg = args.at<Object>(0);
10359
10360 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010363 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364}
10365
10366
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010367// Change the state of break on exceptions.
10368// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10369// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010370RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010371 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010373 RUNTIME_ASSERT(args[0]->IsNumber());
10374 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010375
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010376 // If the number doesn't match an enum value, the ChangeBreakOnException
10377 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010378 ExceptionBreakType type =
10379 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010380 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 isolate->debug()->ChangeBreakOnException(type, enable);
10382 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010383}
10384
10385
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010386// Returns the state of break on exceptions
10387// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010388RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010389 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010390 ASSERT(args.length() == 1);
10391 RUNTIME_ASSERT(args[0]->IsNumber());
10392
10393 ExceptionBreakType type =
10394 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010396 return Smi::FromInt(result);
10397}
10398
10399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400// Prepare for stepping
10401// args[0]: break id for checking execution state
10402// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010403// args[2]: number of times to perform the step, for step out it is the number
10404// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010405RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 ASSERT(args.length() == 3);
10408 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010409 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010410 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10411 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010412 if (!maybe_check->ToObject(&check)) return maybe_check;
10413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010415 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416 }
10417
10418 // Get the step action and check validity.
10419 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10420 if (step_action != StepIn &&
10421 step_action != StepNext &&
10422 step_action != StepOut &&
10423 step_action != StepInMin &&
10424 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010425 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010426 }
10427
10428 // Get the number of steps.
10429 int step_count = NumberToInt32(args[2]);
10430 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010431 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432 }
10433
ager@chromium.orga1645e22009-09-09 19:27:10 +000010434 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010435 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010437 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10439 step_count);
10440 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441}
10442
10443
10444// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010445RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010447 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 isolate->debug()->ClearStepping();
10449 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010450}
10451
10452
10453// Creates a copy of the with context chain. The copy of the context chain is
10454// is linked to the function context supplied.
10455static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10456 Handle<Context> function_context) {
10457 // At the bottom of the chain. Return the function context to link to.
10458 if (context_chain->is_function_context()) {
10459 return function_context;
10460 }
10461
10462 // Recursively copy the with contexts.
10463 Handle<Context> previous(context_chain->previous());
10464 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010465 Handle<Context> context = CopyWithContextChain(function_context, previous);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010466 return context->GetIsolate()->factory()->NewWithContext(
10467 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010468}
10469
10470
10471// Helper function to find or create the arguments object for
10472// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473static Handle<Object> GetArgumentsObject(Isolate* isolate,
10474 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010476 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477 const ScopeInfo<>* sinfo,
10478 Handle<Context> function_context) {
10479 // Try to find the value of 'arguments' to pass as parameter. If it is not
10480 // found (that is the debugged function does not reference 'arguments' and
10481 // does not support eval) then create an 'arguments' object.
10482 int index;
10483 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010484 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010487 }
10488 }
10489
10490 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010491 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10492 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010494 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 }
10496 }
10497
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010498 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010499 Handle<JSObject> arguments =
10500 isolate->factory()->NewArgumentsObject(function, length);
10501 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010502
10503 AssertNoAllocation no_gc;
10504 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010506 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010508 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509 return arguments;
10510}
10511
10512
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010513static const char kSourceStr[] =
10514 "(function(arguments,__source__){return eval(__source__);})";
10515
10516
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010518// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519// extension part has all the parameters and locals of the function on the
10520// stack frame. A function which calls eval with the code to evaluate is then
10521// compiled in this context and called in this context. As this context
10522// replaces the context of the function on the stack frame a new (empty)
10523// function is created as well to be used as the closure for the context.
10524// This function and the context acts as replacements for the function on the
10525// stack frame presenting the same view of the values of parameters and
10526// local variables as if the piece of JavaScript was evaluated at the point
10527// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010528RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010529 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530
10531 // Check the execution state and decode arguments frame and source to be
10532 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010533 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010534 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010535 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10536 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010537 if (!maybe_check_result->ToObject(&check_result)) {
10538 return maybe_check_result;
10539 }
10540 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010541 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10542 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010543 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010544 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010545
10546 // Handle the processing of break.
10547 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548
10549 // Get the frame where the debugging is performed.
10550 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010551 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010552 JavaScriptFrame* frame = it.frame();
10553 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010554 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010555 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556
10557 // Traverse the saved contexts chain to find the active context for the
10558 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010559 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010560 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 save = save->prev();
10562 }
10563 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 SaveContext savex(isolate);
10565 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566
10567 // Create the (empty) function replacing the function on the stack frame for
10568 // the purpose of evaluating in the context created below. It is important
10569 // that this function does not describe any parameters and local variables
10570 // in the context. If it does then this will cause problems with the lookup
10571 // in Context::Lookup, where context slots for parameters and local variables
10572 // are looked at before the extension object.
10573 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010574 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10575 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576 go_between->set_context(function->context());
10577#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010578 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10580 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10581#endif
10582
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010583 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10585 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586
10587 // Allocate a new context for the debug evaluation and set the extension
10588 // object build.
10589 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10591 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010592 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010594 Handle<Context> frame_context(Context::cast(frame->context()));
10595 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 context = CopyWithContextChain(frame_context, context);
10597
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010598 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010599 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010600 Handle<JSObject>::cast(additional_context), false);
10601 }
10602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603 // Wrap the evaluation statement in a new function compiled in the newly
10604 // created context. The function has one parameter which has to be called
10605 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010606 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 isolate->factory()->NewStringFromAscii(
10611 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010612
10613 // Currently, the eval code will be executed in non-strict mode,
10614 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010615 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010616 Compiler::CompileEval(function_source,
10617 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010618 context->IsGlobalContext(),
10619 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010620 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623
10624 // Invoke the result of the compilation to get the evaluation function.
10625 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 Handle<Object> evaluation_function =
10628 Execution::Call(compiled_function, receiver, 0, NULL,
10629 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010630 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10633 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010634 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635
10636 // Invoke the evaluation function and return the result.
10637 const int argc = 2;
10638 Object** argv[argc] = { arguments.location(),
10639 Handle<Object>::cast(source).location() };
10640 Handle<Object> result =
10641 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10642 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010643 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010644
10645 // Skip the global proxy as it has no properties and always delegates to the
10646 // real global object.
10647 if (result->IsJSGlobalProxy()) {
10648 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10649 }
10650
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651 return *result;
10652}
10653
10654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010655RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657
10658 // Check the execution state and decode arguments frame and source to be
10659 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010660 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010661 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010662 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10663 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010664 if (!maybe_check_result->ToObject(&check_result)) {
10665 return maybe_check_result;
10666 }
10667 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010669 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010670 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010671
10672 // Handle the processing of break.
10673 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674
10675 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010676 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010677 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010678 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 top = top->prev();
10680 }
10681 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010682 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 }
10684
10685 // Get the global context now set to the top context from before the
10686 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010687 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010688
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010689 bool is_global = true;
10690
10691 if (additional_context->IsJSObject()) {
10692 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10694 isolate->factory()->empty_string(),
10695 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010696 go_between->set_context(*context);
10697 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010698 isolate->factory()->NewFunctionContext(
10699 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010700 context->set_extension(JSObject::cast(*additional_context));
10701 is_global = false;
10702 }
10703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010705 // Currently, the eval code will be executed in non-strict mode,
10706 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010707 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010708 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010709 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010711 Handle<JSFunction>(
10712 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10713 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010714
10715 // Invoke the result of the compilation to get the evaluation function.
10716 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010717 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718 Handle<Object> result =
10719 Execution::Call(compiled_function, receiver, 0, NULL,
10720 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010721 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722 return *result;
10723}
10724
10725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010726RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010728 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010731 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010732
10733 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010734 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010735 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10736 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10737 // because using
10738 // instances->set(i, *GetScriptWrapper(script))
10739 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10740 // already have deferenced the instances handle.
10741 Handle<JSValue> wrapper = GetScriptWrapper(script);
10742 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 }
10744
10745 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010746 Handle<JSObject> result =
10747 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010748 Handle<JSArray>::cast(result)->SetContent(*instances);
10749 return *result;
10750}
10751
10752
10753// Helper function used by Runtime_DebugReferencedBy below.
10754static int DebugReferencedBy(JSObject* target,
10755 Object* instance_filter, int max_references,
10756 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757 JSFunction* arguments_function) {
10758 NoHandleAllocation ha;
10759 AssertNoAllocation no_alloc;
10760
10761 // Iterate the heap.
10762 int count = 0;
10763 JSObject* last = NULL;
10764 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010765 HeapObject* heap_obj = NULL;
10766 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010767 (max_references == 0 || count < max_references)) {
10768 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769 if (heap_obj->IsJSObject()) {
10770 // Skip context extension objects and argument arrays as these are
10771 // checked in the context of functions using them.
10772 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010773 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 obj->map()->constructor() == arguments_function) {
10775 continue;
10776 }
10777
10778 // Check if the JS object has a reference to the object looked for.
10779 if (obj->ReferencesObject(target)) {
10780 // Check instance filter if supplied. This is normally used to avoid
10781 // references from mirror objects (see Runtime_IsInPrototypeChain).
10782 if (!instance_filter->IsUndefined()) {
10783 Object* V = obj;
10784 while (true) {
10785 Object* prototype = V->GetPrototype();
10786 if (prototype->IsNull()) {
10787 break;
10788 }
10789 if (instance_filter == prototype) {
10790 obj = NULL; // Don't add this object.
10791 break;
10792 }
10793 V = prototype;
10794 }
10795 }
10796
10797 if (obj != NULL) {
10798 // Valid reference found add to instance array if supplied an update
10799 // count.
10800 if (instances != NULL && count < instances_size) {
10801 instances->set(count, obj);
10802 }
10803 last = obj;
10804 count++;
10805 }
10806 }
10807 }
10808 }
10809
10810 // Check for circular reference only. This can happen when the object is only
10811 // referenced from mirrors and has a circular reference in which case the
10812 // object is not really alive and would have been garbage collected if not
10813 // referenced from the mirror.
10814 if (count == 1 && last == target) {
10815 count = 0;
10816 }
10817
10818 // Return the number of referencing objects found.
10819 return count;
10820}
10821
10822
10823// Scan the heap for objects with direct references to an object
10824// args[0]: the object to find references to
10825// args[1]: constructor function for instances to exclude (Mirror)
10826// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010827RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010828 ASSERT(args.length() == 3);
10829
10830 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832
10833 // Check parameters.
10834 CONVERT_CHECKED(JSObject, target, args[0]);
10835 Object* instance_filter = args[1];
10836 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10837 instance_filter->IsJSObject());
10838 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10839 RUNTIME_ASSERT(max_references >= 0);
10840
10841 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844 JSFunction* arguments_function =
10845 JSFunction::cast(arguments_boilerplate->map()->constructor());
10846
10847 // Get the number of referencing objects.
10848 int count;
10849 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010850 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851
10852 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010853 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010855 if (!maybe_object->ToObject(&object)) return maybe_object;
10856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857 FixedArray* instances = FixedArray::cast(object);
10858
10859 // Fill the referencing objects.
10860 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010861 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862
10863 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010864 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10866 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010867 if (!maybe_result->ToObject(&result)) return maybe_result;
10868 }
10869 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010870 return result;
10871}
10872
10873
10874// Helper function used by Runtime_DebugConstructedBy below.
10875static int DebugConstructedBy(JSFunction* constructor, int max_references,
10876 FixedArray* instances, int instances_size) {
10877 AssertNoAllocation no_alloc;
10878
10879 // Iterate the heap.
10880 int count = 0;
10881 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010882 HeapObject* heap_obj = NULL;
10883 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884 (max_references == 0 || count < max_references)) {
10885 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886 if (heap_obj->IsJSObject()) {
10887 JSObject* obj = JSObject::cast(heap_obj);
10888 if (obj->map()->constructor() == constructor) {
10889 // Valid reference found add to instance array if supplied an update
10890 // count.
10891 if (instances != NULL && count < instances_size) {
10892 instances->set(count, obj);
10893 }
10894 count++;
10895 }
10896 }
10897 }
10898
10899 // Return the number of referencing objects found.
10900 return count;
10901}
10902
10903
10904// Scan the heap for objects constructed by a specific function.
10905// args[0]: the constructor to find instances of
10906// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010907RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010908 ASSERT(args.length() == 2);
10909
10910 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010911 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912
10913 // Check parameters.
10914 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10915 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10916 RUNTIME_ASSERT(max_references >= 0);
10917
10918 // Get the number of referencing objects.
10919 int count;
10920 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10921
10922 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010923 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010925 if (!maybe_object->ToObject(&object)) return maybe_object;
10926 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927 FixedArray* instances = FixedArray::cast(object);
10928
10929 // Fill the referencing objects.
10930 count = DebugConstructedBy(constructor, max_references, instances, count);
10931
10932 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010933 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010934 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10935 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010936 if (!maybe_result->ToObject(&result)) return maybe_result;
10937 }
10938 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010939 return result;
10940}
10941
10942
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010943// Find the effective prototype object as returned by __proto__.
10944// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010945RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 ASSERT(args.length() == 1);
10947
10948 CONVERT_CHECKED(JSObject, obj, args[0]);
10949
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010950 // Use the __proto__ accessor.
10951 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952}
10953
10954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010955RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000010956 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010957 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010958 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959}
10960
10961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010962RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010963#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010964 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010965 ASSERT(args.length() == 1);
10966 // Get the function and make sure it is compiled.
10967 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010968 Handle<SharedFunctionInfo> shared(func->shared());
10969 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010970 return Failure::Exception();
10971 }
10972 func->code()->PrintLn();
10973#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010975}
ager@chromium.org9085a012009-05-11 19:22:57 +000010976
10977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010978RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010979#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010981 ASSERT(args.length() == 1);
10982 // Get the function and make sure it is compiled.
10983 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010984 Handle<SharedFunctionInfo> shared(func->shared());
10985 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010986 return Failure::Exception();
10987 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010988 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010989#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010991}
10992
10993
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010994RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010995 NoHandleAllocation ha;
10996 ASSERT(args.length() == 1);
10997
10998 CONVERT_CHECKED(JSFunction, f, args[0]);
10999 return f->shared()->inferred_name();
11000}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011001
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011002
11003static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011004 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011005 AssertNoAllocation no_allocations;
11006
11007 int counter = 0;
11008 int buffer_size = buffer->length();
11009 HeapIterator iterator;
11010 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11011 ASSERT(obj != NULL);
11012 if (!obj->IsSharedFunctionInfo()) {
11013 continue;
11014 }
11015 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11016 if (shared->script() != script) {
11017 continue;
11018 }
11019 if (counter < buffer_size) {
11020 buffer->set(counter, shared);
11021 }
11022 counter++;
11023 }
11024 return counter;
11025}
11026
11027// For a script finds all SharedFunctionInfo's in the heap that points
11028// to this script. Returns JSArray of SharedFunctionInfo wrapped
11029// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011030RUNTIME_FUNCTION(MaybeObject*,
11031 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011032 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011033 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011034 CONVERT_CHECKED(JSValue, script_value, args[0]);
11035
11036 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11037
11038 const int kBufferSize = 32;
11039
11040 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011041 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011042 int number = FindSharedFunctionInfosForScript(*script, *array);
11043 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011044 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011045 FindSharedFunctionInfosForScript(*script, *array);
11046 }
11047
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011049 result->set_length(Smi::FromInt(number));
11050
11051 LiveEdit::WrapSharedFunctionInfos(result);
11052
11053 return *result;
11054}
11055
11056// For a script calculates compilation information about all its functions.
11057// The script source is explicitly specified by the second argument.
11058// The source of the actual script is not used, however it is important that
11059// all generated code keeps references to this particular instance of script.
11060// Returns a JSArray of compilation infos. The array is ordered so that
11061// each function with all its descendant is always stored in a continues range
11062// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011063RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011064 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011065 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011066 CONVERT_CHECKED(JSValue, script, args[0]);
11067 CONVERT_ARG_CHECKED(String, source, 1);
11068 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11069
11070 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011073 return Failure::Exception();
11074 }
11075
11076 return result;
11077}
11078
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011079// Changes the source of the script to a new_source.
11080// If old_script_name is provided (i.e. is a String), also creates a copy of
11081// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011082RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011083 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011084 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011085 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11086 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011088
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011089 CONVERT_CHECKED(Script, original_script_pointer,
11090 original_script_value->value());
11091 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011092
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011093 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11094 new_source,
11095 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011096
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011097 if (old_script->IsScript()) {
11098 Handle<Script> script_handle(Script::cast(old_script));
11099 return *(GetScriptWrapper(script_handle));
11100 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011101 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011102 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011103}
11104
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011106RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011107 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011108 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011109 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11110 return LiveEdit::FunctionSourceUpdated(shared_info);
11111}
11112
11113
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011114// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011115RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011116 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011118 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11119 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11120
ager@chromium.orgac091b72010-05-05 07:34:42 +000011121 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011122}
11123
11124// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011125RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011126 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011127 HandleScope scope(isolate);
11128 Handle<Object> function_object(args[0], isolate);
11129 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011130
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011131 if (function_object->IsJSValue()) {
11132 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11133 if (script_object->IsJSValue()) {
11134 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011135 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011136 }
11137
11138 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11139 } else {
11140 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11141 // and we check it in this function.
11142 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011144 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011145}
11146
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011147
11148// In a code of a parent function replaces original function as embedded object
11149// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011150RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011151 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011152 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011153
11154 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11155 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11156 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11157
11158 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11159 subst_wrapper);
11160
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011161 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011162}
11163
11164
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011165// Updates positions of a shared function info (first parameter) according
11166// to script source change. Text change is described in second parameter as
11167// array of groups of 3 numbers:
11168// (change_begin, change_end, change_end_new_position).
11169// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011170RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011171 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011172 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011173 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11174 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11175
ager@chromium.orgac091b72010-05-05 07:34:42 +000011176 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011177}
11178
11179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011180// For array of SharedFunctionInfo's (each wrapped in JSValue)
11181// checks that none of them have activations on stacks (of any thread).
11182// Returns array of the same length with corresponding results of
11183// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011184RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011185 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011187 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011188 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011189
ager@chromium.org357bf652010-04-12 11:30:10 +000011190 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011191}
11192
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011193// Compares 2 strings line-by-line, then token-wise and returns diff in form
11194// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11195// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011196RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011197 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011198 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011199 CONVERT_ARG_CHECKED(String, s1, 0);
11200 CONVERT_ARG_CHECKED(String, s2, 1);
11201
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011202 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011203}
11204
11205
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011206// A testing entry. Returns statement position which is the closest to
11207// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011208RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011209 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011210 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011211 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11212 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011215
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011216 if (code->kind() != Code::FUNCTION &&
11217 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011218 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011219 }
11220
11221 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011222 int closest_pc = 0;
11223 int distance = kMaxInt;
11224 while (!it.done()) {
11225 int statement_position = static_cast<int>(it.rinfo()->data());
11226 // Check if this break point is closer that what was previously found.
11227 if (source_position <= statement_position &&
11228 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011229 closest_pc =
11230 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011231 distance = statement_position - source_position;
11232 // Check whether we can't get any closer.
11233 if (distance == 0) break;
11234 }
11235 it.next();
11236 }
11237
11238 return Smi::FromInt(closest_pc);
11239}
11240
11241
ager@chromium.org357bf652010-04-12 11:30:10 +000011242// Calls specified function with or without entering the debugger.
11243// This is used in unit tests to run code as if debugger is entered or simply
11244// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011245RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011246 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011248 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11249 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11250
11251 Handle<Object> result;
11252 bool pending_exception;
11253 {
11254 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011255 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011256 &pending_exception);
11257 } else {
11258 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011259 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011260 &pending_exception);
11261 }
11262 }
11263 if (!pending_exception) {
11264 return *result;
11265 } else {
11266 return Failure::Exception();
11267 }
11268}
11269
11270
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011271// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011272RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011273 CONVERT_CHECKED(String, arg, args[0]);
11274 SmartPointer<char> flags =
11275 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11276 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011277 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011278}
11279
11280
11281// Performs a GC.
11282// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011283RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011284 isolate->heap()->CollectAllGarbage(true);
11285 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011286}
11287
11288
11289// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011290RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011292 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011293 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011294 }
11295 return Smi::FromInt(usage);
11296}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011297
11298
11299// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011300RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011301#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011303#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011304 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011305#endif
11306}
11307
11308
11309// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011310RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011311#ifdef LIVE_OBJECT_LIST
11312 return LiveObjectList::Capture();
11313#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011315#endif
11316}
11317
11318
11319// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011320RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011321#ifdef LIVE_OBJECT_LIST
11322 CONVERT_SMI_CHECKED(id, args[0]);
11323 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011324 return success ? isolate->heap()->true_value() :
11325 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011326#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011328#endif
11329}
11330
11331
11332// Generates the response to a debugger request for a dump of the objects
11333// contained in the difference between the captured live object lists
11334// specified by id1 and id2.
11335// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11336// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011337RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011338#ifdef LIVE_OBJECT_LIST
11339 HandleScope scope;
11340 CONVERT_SMI_CHECKED(id1, args[0]);
11341 CONVERT_SMI_CHECKED(id2, args[1]);
11342 CONVERT_SMI_CHECKED(start, args[2]);
11343 CONVERT_SMI_CHECKED(count, args[3]);
11344 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11345 EnterDebugger enter_debugger;
11346 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11347#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011348 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011349#endif
11350}
11351
11352
11353// Gets the specified object as requested by the debugger.
11354// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011355RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011356#ifdef LIVE_OBJECT_LIST
11357 CONVERT_SMI_CHECKED(obj_id, args[0]);
11358 Object* result = LiveObjectList::GetObj(obj_id);
11359 return result;
11360#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011361 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011362#endif
11363}
11364
11365
11366// Gets the obj id for the specified address if valid.
11367// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011368RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011369#ifdef LIVE_OBJECT_LIST
11370 HandleScope scope;
11371 CONVERT_ARG_CHECKED(String, address, 0);
11372 Object* result = LiveObjectList::GetObjId(address);
11373 return result;
11374#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011376#endif
11377}
11378
11379
11380// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011382#ifdef LIVE_OBJECT_LIST
11383 HandleScope scope;
11384 CONVERT_SMI_CHECKED(obj_id, args[0]);
11385 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11386 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11387 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11388 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11389 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11390
11391 Handle<JSObject> instance_filter;
11392 if (args[1]->IsJSObject()) {
11393 instance_filter = args.at<JSObject>(1);
11394 }
11395 bool verbose = false;
11396 if (args[2]->IsBoolean()) {
11397 verbose = args[2]->IsTrue();
11398 }
11399 int start = 0;
11400 if (args[3]->IsSmi()) {
11401 start = Smi::cast(args[3])->value();
11402 }
11403 int limit = Smi::kMaxValue;
11404 if (args[4]->IsSmi()) {
11405 limit = Smi::cast(args[4])->value();
11406 }
11407
11408 return LiveObjectList::GetObjRetainers(obj_id,
11409 instance_filter,
11410 verbose,
11411 start,
11412 limit,
11413 filter_obj);
11414#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011416#endif
11417}
11418
11419
11420// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011421RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011422#ifdef LIVE_OBJECT_LIST
11423 HandleScope scope;
11424 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11425 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11426 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11427
11428 Handle<JSObject> instance_filter;
11429 if (args[2]->IsJSObject()) {
11430 instance_filter = args.at<JSObject>(2);
11431 }
11432
11433 Object* result =
11434 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11435 return result;
11436#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011438#endif
11439}
11440
11441
11442// Generates the response to a debugger request for a list of all
11443// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011444RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011445#ifdef LIVE_OBJECT_LIST
11446 CONVERT_SMI_CHECKED(start, args[0]);
11447 CONVERT_SMI_CHECKED(count, args[1]);
11448 return LiveObjectList::Info(start, count);
11449#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011451#endif
11452}
11453
11454
11455// Gets a dump of the specified object as requested by the debugger.
11456// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011457RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011458#ifdef LIVE_OBJECT_LIST
11459 HandleScope scope;
11460 CONVERT_SMI_CHECKED(obj_id, args[0]);
11461 Object* result = LiveObjectList::PrintObj(obj_id);
11462 return result;
11463#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011465#endif
11466}
11467
11468
11469// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011470RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011471#ifdef LIVE_OBJECT_LIST
11472 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011474#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011475 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011476#endif
11477}
11478
11479
11480// Generates the response to a debugger request for a summary of the types
11481// of objects in the difference between the captured live object lists
11482// specified by id1 and id2.
11483// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11484// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011485RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011486#ifdef LIVE_OBJECT_LIST
11487 HandleScope scope;
11488 CONVERT_SMI_CHECKED(id1, args[0]);
11489 CONVERT_SMI_CHECKED(id2, args[1]);
11490 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11491
11492 EnterDebugger enter_debugger;
11493 return LiveObjectList::Summarize(id1, id2, filter_obj);
11494#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011495 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011496#endif
11497}
11498
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011499#endif // ENABLE_DEBUGGER_SUPPORT
11500
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011501
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011502#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011503RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011504 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011505 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011506
11507 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011508 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11509 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011510 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011511}
11512
11513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011515 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011516 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011517
11518 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011519 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11520 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011521 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011522}
11523
11524#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011526// Finds the script object from the script data. NOTE: This operation uses
11527// heap traversal to find the function generated for the source position
11528// for the requested break point. For lazily compiled functions several heap
11529// traversals might be required rendering this operation as a rather slow
11530// operation. However for setting break points which is normally done through
11531// some kind of user interaction the performance is not crucial.
11532static Handle<Object> Runtime_GetScriptFromScriptName(
11533 Handle<String> script_name) {
11534 // Scan the heap for Script objects to find the script with the requested
11535 // script data.
11536 Handle<Script> script;
11537 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011538 HeapObject* obj = NULL;
11539 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540 // If a script is found check if it has the script data requested.
11541 if (obj->IsScript()) {
11542 if (Script::cast(obj)->name()->IsString()) {
11543 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11544 script = Handle<Script>(Script::cast(obj));
11545 }
11546 }
11547 }
11548 }
11549
11550 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552
11553 // Return the script found.
11554 return GetScriptWrapper(script);
11555}
11556
11557
11558// Get the script object from script data. NOTE: Regarding performance
11559// see the NOTE for GetScriptFromScriptData.
11560// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011561RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563
11564 ASSERT(args.length() == 1);
11565
11566 CONVERT_CHECKED(String, script_name, args[0]);
11567
11568 // Find the requested script.
11569 Handle<Object> result =
11570 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11571 return *result;
11572}
11573
11574
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011575// Determines whether the given stack frame should be displayed in
11576// a stack trace. The caller is the error constructor that asked
11577// for the stack trace to be collected. The first time a construct
11578// call to this function is encountered it is skipped. The seen_caller
11579// in/out parameter is used to remember if the caller has been seen
11580// yet.
11581static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11582 bool* seen_caller) {
11583 // Only display JS frames.
11584 if (!raw_frame->is_java_script())
11585 return false;
11586 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11587 Object* raw_fun = frame->function();
11588 // Not sure when this can happen but skip it just in case.
11589 if (!raw_fun->IsJSFunction())
11590 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011591 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011592 *seen_caller = true;
11593 return false;
11594 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011595 // Skip all frames until we've seen the caller. Also, skip the most
11596 // obvious builtin calls. Some builtin calls (such as Number.ADD
11597 // which is invoked using 'call') are very difficult to recognize
11598 // so we're leaving them in for now.
11599 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011600}
11601
11602
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011603// Collect the raw data for a stack trace. Returns an array of 4
11604// element segments each containing a receiver, function, code and
11605// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011606RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011607 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011608 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011609 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11610
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 HandleScope scope(isolate);
11612 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011613
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011614 limit = Max(limit, 0); // Ensure that limit is not negative.
11615 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011616 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011617 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011618
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011619 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011620 // If the caller parameter is a function we skip frames until we're
11621 // under it before starting to collect.
11622 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011623 int cursor = 0;
11624 int frames_seen = 0;
11625 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011626 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011627 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011628 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011629 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011630 // Set initial size to the maximum inlining level + 1 for the outermost
11631 // function.
11632 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011633 frame->Summarize(&frames);
11634 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011635 if (cursor + 4 > elements->length()) {
11636 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11637 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011639 for (int i = 0; i < cursor; i++) {
11640 new_elements->set(i, elements->get(i));
11641 }
11642 elements = new_elements;
11643 }
11644 ASSERT(cursor + 4 <= elements->length());
11645
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011646 Handle<Object> recv = frames[i].receiver();
11647 Handle<JSFunction> fun = frames[i].function();
11648 Handle<Code> code = frames[i].code();
11649 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011650 elements->set(cursor++, *recv);
11651 elements->set(cursor++, *fun);
11652 elements->set(cursor++, *code);
11653 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011654 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011655 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011656 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011657 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011659 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011660 return *result;
11661}
11662
11663
ager@chromium.org3811b432009-10-28 14:53:37 +000011664// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011665RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011666 ASSERT_EQ(args.length(), 0);
11667
11668 NoHandleAllocation ha;
11669
11670 const char* version_string = v8::V8::GetVersion();
11671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11673 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011674}
11675
11676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011677RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011678 ASSERT(args.length() == 2);
11679 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11680 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011682 OS::Abort();
11683 UNREACHABLE();
11684 return NULL;
11685}
11686
11687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011688RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011689 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011690 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011691 Object* key = args[1];
11692
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011693 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011694 Object* o = cache->get(finger_index);
11695 if (o == key) {
11696 // The fastest case: hit the same place again.
11697 return cache->get(finger_index + 1);
11698 }
11699
11700 for (int i = finger_index - 2;
11701 i >= JSFunctionResultCache::kEntriesIndex;
11702 i -= 2) {
11703 o = cache->get(i);
11704 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011705 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011706 return cache->get(i + 1);
11707 }
11708 }
11709
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011710 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011711 ASSERT(size <= cache->length());
11712
11713 for (int i = size - 2; i > finger_index; i -= 2) {
11714 o = cache->get(i);
11715 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011716 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011717 return cache->get(i + 1);
11718 }
11719 }
11720
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011721 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011722 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011723
11724 Handle<JSFunctionResultCache> cache_handle(cache);
11725 Handle<Object> key_handle(key);
11726 Handle<Object> value;
11727 {
11728 Handle<JSFunction> factory(JSFunction::cast(
11729 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11730 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011731 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011732 // This handle is nor shared, nor used later, so it's safe.
11733 Object** argv[] = { key_handle.location() };
11734 bool pending_exception = false;
11735 value = Execution::Call(factory,
11736 receiver,
11737 1,
11738 argv,
11739 &pending_exception);
11740 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011741 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011742
11743#ifdef DEBUG
11744 cache_handle->JSFunctionResultCacheVerify();
11745#endif
11746
11747 // Function invocation may have cleared the cache. Reread all the data.
11748 finger_index = cache_handle->finger_index();
11749 size = cache_handle->size();
11750
11751 // If we have spare room, put new data into it, otherwise evict post finger
11752 // entry which is likely to be the least recently used.
11753 int index = -1;
11754 if (size < cache_handle->length()) {
11755 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11756 index = size;
11757 } else {
11758 index = finger_index + JSFunctionResultCache::kEntrySize;
11759 if (index == cache_handle->length()) {
11760 index = JSFunctionResultCache::kEntriesIndex;
11761 }
11762 }
11763
11764 ASSERT(index % 2 == 0);
11765 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11766 ASSERT(index < cache_handle->length());
11767
11768 cache_handle->set(index, *key_handle);
11769 cache_handle->set(index + 1, *value);
11770 cache_handle->set_finger_index(index);
11771
11772#ifdef DEBUG
11773 cache_handle->JSFunctionResultCacheVerify();
11774#endif
11775
11776 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011777}
11778
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011780RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011782 CONVERT_ARG_CHECKED(String, type, 0);
11783 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 return *isolate->factory()->NewJSMessageObject(
11785 type,
11786 arguments,
11787 0,
11788 0,
11789 isolate->factory()->undefined_value(),
11790 isolate->factory()->undefined_value(),
11791 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011792}
11793
11794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011795RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011796 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11797 return message->type();
11798}
11799
11800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011801RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011802 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11803 return message->arguments();
11804}
11805
11806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011807RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011808 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11809 return Smi::FromInt(message->start_position());
11810}
11811
11812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011813RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011814 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11815 return message->script();
11816}
11817
11818
kasper.lund44510672008-07-25 07:37:58 +000011819#ifdef DEBUG
11820// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11821// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011822RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000011823 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011825#define COUNT_ENTRY(Name, argc, ressize) + 1
11826 int entry_count = 0
11827 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11828 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11829 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11830#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831 Factory* factory = isolate->factory();
11832 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011834 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011835#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 { \
11837 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011838 Handle<String> name; \
11839 /* Inline runtime functions have an underscore in front of the name. */ \
11840 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011841 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011842 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11843 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011845 Vector<const char>(#Name, StrLength(#Name))); \
11846 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011847 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011848 pair_elements->set(0, *name); \
11849 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011851 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011853 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011855 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011856 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011857 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011859 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861 return *result;
11862}
kasper.lund44510672008-07-25 07:37:58 +000011863#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864
11865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011866RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011867 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011868 CONVERT_CHECKED(String, format, args[0]);
11869 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011870 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 LOGGER->LogRuntime(chars, elms);
11872 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011873}
11874
11875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 UNREACHABLE(); // implemented as macro in the parser
11878 return NULL;
11879}
11880
11881
11882// ----------------------------------------------------------------------------
11883// Implementation of Runtime
11884
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011885#define F(name, number_of_args, result_size) \
11886 { Runtime::k##name, Runtime::RUNTIME, #name, \
11887 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011889
11890#define I(name, number_of_args, result_size) \
11891 { Runtime::kInline##name, Runtime::INLINE, \
11892 "_" #name, NULL, number_of_args, result_size },
11893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011896 INLINE_FUNCTION_LIST(I)
11897 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011898};
11899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
11902 Object* dictionary) {
11903 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011904 ASSERT(dictionary != NULL);
11905 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11906 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011907 Object* name_symbol;
11908 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011910 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11911 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011912 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011913 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11914 String::cast(name_symbol),
11915 Smi::FromInt(i),
11916 PropertyDetails(NONE, NORMAL));
11917 if (!maybe_dictionary->ToObject(&dictionary)) {
11918 // Non-recoverable failure. Calling code must restart heap
11919 // initialization.
11920 return maybe_dictionary;
11921 }
11922 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011923 }
11924 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925}
11926
11927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011928const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11929 Heap* heap = name->GetHeap();
11930 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011931 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011933 int function_index = Smi::cast(smi_index)->value();
11934 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 }
11936 return NULL;
11937}
11938
11939
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011940const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011941 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11942}
11943
11944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011945void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011946 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011948 if (failure->IsRetryAfterGC()) {
11949 // Try to do a garbage collection; ignore it if it fails. The C
11950 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011951 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011952 } else {
11953 // Handle last resort GC and make sure to allow future allocations
11954 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011955 isolate->counters()->gc_last_resort_from_js()->Increment();
11956 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958}
11959
11960
11961} } // namespace v8::internal