blob: 07f18ee7bc6c94bb59398dffedf94f634eae54a2 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000084// Cast the given argument to a Smi and store its value in an int variable
85// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000086// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087#define CONVERT_SMI_ARG_CHECKED(name, index) \
88 RUNTIME_ASSERT(args[index]->IsSmi()); \
89 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091// Cast the given argument to a double and store it in a variable with
92// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
95 RUNTIME_ASSERT(args[index]->IsNumber()); \
96 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000485 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000502 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000504 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000528 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000530 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000554 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000597 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
603 ASSERT(args.length() == 1);
604 Object* obj = args[0];
605 return obj->IsJSProxy()
606 ? isolate->heap()->true_value() : isolate->heap()->false_value();
607}
608
609
610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
611 ASSERT(args.length() == 1);
612 CONVERT_CHECKED(JSProxy, proxy, args[0]);
613 return proxy->handler();
614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 NoHandleAllocation ha;
619 ASSERT(args.length() == 1);
620 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 return JSObject::cast(obj)->class_name();
623}
624
ager@chromium.org7c537e22008-10-16 08:43:32 +0000625
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000626RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
627 NoHandleAllocation ha;
628 ASSERT(args.length() == 1);
629 Object* obj = args[0];
630 obj = obj->GetPrototype();
631 while (obj->IsJSObject() &&
632 JSObject::cast(obj)->map()->is_hidden_prototype()) {
633 obj = obj->GetPrototype();
634 }
635 return obj;
636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000656 NoHandleAllocation ha;
657 ASSERT(args.length() == 2);
658 CONVERT_CHECKED(JSObject, jsobject, args[0]);
659 CONVERT_CHECKED(JSObject, proto, args[1]);
660
661 // Sanity checks. The old prototype (that we are replacing) could
662 // theoretically be null, but if it is not null then check that we
663 // didn't already install a hidden prototype here.
664 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
665 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
666 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
667
668 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 Object* map_or_failure;
670 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
671 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
672 return maybe_map_or_failure;
673 }
674 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000675 Map* new_proto_map = Map::cast(map_or_failure);
676
lrn@chromium.org303ada72010-10-27 09:33:13 +0000677 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
678 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
679 return maybe_map_or_failure;
680 }
681 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000682 Map* new_map = Map::cast(map_or_failure);
683
684 // Set proto's prototype to be the old prototype of the object.
685 new_proto_map->set_prototype(jsobject->GetPrototype());
686 proto->set_map(new_proto_map);
687 new_proto_map->set_is_hidden_prototype();
688
689 // Set the object's prototype to proto.
690 new_map->set_prototype(proto);
691 jsobject->set_map(new_map);
692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000694}
695
696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000697RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000699 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000700 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702}
703
704
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000705// Recursively traverses hidden prototypes if property is not found
706static void GetOwnPropertyImplementation(JSObject* obj,
707 String* name,
708 LookupResult* result) {
709 obj->LocalLookupRealNamedProperty(name, result);
710
711 if (!result->IsProperty()) {
712 Object* proto = obj->GetPrototype();
713 if (proto->IsJSObject() &&
714 JSObject::cast(proto)->map()->is_hidden_prototype())
715 GetOwnPropertyImplementation(JSObject::cast(proto),
716 name, result);
717 }
718}
719
720
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000721static bool CheckAccessException(LookupResult* result,
722 v8::AccessType access_type) {
723 if (result->type() == CALLBACKS) {
724 Object* callback = result->GetCallbackObject();
725 if (callback->IsAccessorInfo()) {
726 AccessorInfo* info = AccessorInfo::cast(callback);
727 bool can_access =
728 (access_type == v8::ACCESS_HAS &&
729 (info->all_can_read() || info->all_can_write())) ||
730 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
731 (access_type == v8::ACCESS_SET && info->all_can_write());
732 return can_access;
733 }
734 }
735
736 return false;
737}
738
739
740static bool CheckAccess(JSObject* obj,
741 String* name,
742 LookupResult* result,
743 v8::AccessType access_type) {
744 ASSERT(result->IsProperty());
745
746 JSObject* holder = result->holder();
747 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000749 while (true) {
750 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Access check callback denied the access, but some properties
753 // can have a special permissions which override callbacks descision
754 // (currently see v8::AccessControl).
755 break;
756 }
757
758 if (current == holder) {
759 return true;
760 }
761
762 current = JSObject::cast(current->GetPrototype());
763 }
764
765 // API callbacks can have per callback access exceptions.
766 switch (result->type()) {
767 case CALLBACKS: {
768 if (CheckAccessException(result, access_type)) {
769 return true;
770 }
771 break;
772 }
773 case INTERCEPTOR: {
774 // If the object has an interceptor, try real named properties.
775 // Overwrite the result to fetch the correct property later.
776 holder->LookupRealNamedProperty(name, result);
777 if (result->IsProperty()) {
778 if (CheckAccessException(result, access_type)) {
779 return true;
780 }
781 }
782 break;
783 }
784 default:
785 break;
786 }
787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000788 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000789 return false;
790}
791
792
793// TODO(1095): we should traverse hidden prototype hierachy as well.
794static bool CheckElementAccess(JSObject* obj,
795 uint32_t index,
796 v8::AccessType access_type) {
797 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000799 return false;
800 }
801
802 return true;
803}
804
805
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000806// Enumerator used as indices into the array returned from GetOwnProperty
807enum PropertyDescriptorIndices {
808 IS_ACCESSOR_INDEX,
809 VALUE_INDEX,
810 GETTER_INDEX,
811 SETTER_INDEX,
812 WRITABLE_INDEX,
813 ENUMERABLE_INDEX,
814 CONFIGURABLE_INDEX,
815 DESCRIPTOR_SIZE
816};
817
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818// Returns an array with the property description:
819// if args[1] is not a property on args[0]
820// returns undefined
821// if args[1] is a data property on args[0]
822// [false, value, Writeable, Enumerable, Configurable]
823// if args[1] is an accessor on args[0]
824// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 Heap* heap = isolate->heap();
828 HandleScope scope(isolate);
829 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
830 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000832 CONVERT_ARG_CHECKED(JSObject, obj, 0);
833 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835 // This could be an element.
836 uint32_t index;
837 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 switch (obj->HasLocalElement(index)) {
839 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000842 case JSObject::STRING_CHARACTER_ELEMENT: {
843 // Special handling of string objects according to ECMAScript 5
844 // 15.5.5.2. Note that this might be a string object with elements
845 // other than the actual string value. This is covered by the
846 // subsequent cases.
847 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
848 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000849 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 elms->set(WRITABLE_INDEX, heap->false_value());
854 elms->set(ENUMERABLE_INDEX, heap->false_value());
855 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000856 return *desc;
857 }
858
859 case JSObject::INTERCEPTED_ELEMENT:
860 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000864 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 elms->set(WRITABLE_INDEX, heap->true_value());
866 elms->set(ENUMERABLE_INDEX, heap->true_value());
867 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000868 return *desc;
869 }
870
871 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872 Handle<JSObject> holder = obj;
873 if (obj->IsJSGlobalProxy()) {
874 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000876 ASSERT(proto->IsJSGlobalObject());
877 holder = Handle<JSObject>(JSObject::cast(proto));
878 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000879 FixedArray* elements = FixedArray::cast(holder->elements());
880 NumberDictionary* dictionary = NULL;
881 if (elements->map() == heap->non_strict_arguments_elements_map()) {
882 dictionary = NumberDictionary::cast(elements->get(1));
883 } else {
884 dictionary = NumberDictionary::cast(elements);
885 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000886 int entry = dictionary->FindEntry(index);
887 ASSERT(entry != NumberDictionary::kNotFound);
888 PropertyDetails details = dictionary->DetailsAt(entry);
889 switch (details.type()) {
890 case CALLBACKS: {
891 // This is an accessor property with getter and/or setter.
892 FixedArray* callbacks =
893 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000895 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
896 elms->set(GETTER_INDEX, callbacks->get(0));
897 }
898 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
899 elms->set(SETTER_INDEX, callbacks->get(1));
900 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 break;
902 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000906 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000907 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000908 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000911 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 default:
913 UNREACHABLE();
914 break;
915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
917 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 return *desc;
919 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
921 }
922
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000923 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000925
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000926 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000928 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000929
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 }
933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
935 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936
937 bool is_js_accessor = (result.type() == CALLBACKS) &&
938 (result.GetCallbackObject()->IsFixedArray());
939
940 if (is_js_accessor) {
941 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943
944 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
945 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
946 elms->set(GETTER_INDEX, structure->get(0));
947 }
948 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
949 elms->set(SETTER_INDEX, structure->get(1));
950 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000951 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000952 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
953 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000954
955 PropertyAttributes attrs;
956 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000957 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000958 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
959 if (!maybe_value->ToObject(&value)) return maybe_value;
960 }
961 elms->set(VALUE_INDEX, value);
962 }
963
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964 return *desc;
965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(JSObject, obj, args[0]);
971 return obj->PreventExtensions();
972}
973
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000975RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000976 ASSERT(args.length() == 1);
977 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000978 if (obj->IsJSGlobalProxy()) {
979 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000981 ASSERT(proto->IsJSGlobalObject());
982 obj = JSObject::cast(proto);
983 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return obj->map()->is_extensible() ? isolate->heap()->true_value()
985 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986}
987
988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000989RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000992 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
993 CONVERT_ARG_CHECKED(String, pattern, 1);
994 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
996 if (result.is_null()) return Failure::Exception();
997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001004 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 1);
1011 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001012 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014}
1015
1016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001017RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 ASSERT(args.length() == 2);
1019 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001021 int index = field->value();
1022 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1023 InstanceType type = templ->map()->instance_type();
1024 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1025 type == OBJECT_TEMPLATE_INFO_TYPE);
1026 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001027 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001028 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1029 } else {
1030 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1031 }
1032 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033}
1034
1035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001036RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001037 ASSERT(args.length() == 1);
1038 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001039 Map* old_map = object->map();
1040 bool needs_access_checks = old_map->is_access_check_needed();
1041 if (needs_access_checks) {
1042 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001043 Object* new_map;
1044 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1045 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1046 }
ager@chromium.org32912102009-01-16 10:38:43 +00001047
1048 Map::cast(new_map)->set_is_access_check_needed(false);
1049 object->set_map(Map::cast(new_map));
1050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001051 return needs_access_checks ? isolate->heap()->true_value()
1052 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057 ASSERT(args.length() == 1);
1058 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001059 Map* old_map = object->map();
1060 if (!old_map->is_access_check_needed()) {
1061 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001062 Object* new_map;
1063 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1064 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1065 }
ager@chromium.org32912102009-01-16 10:38:43 +00001066
1067 Map::cast(new_map)->set_is_access_check_needed(true);
1068 object->set_map(Map::cast(new_map));
1069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001071}
1072
1073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074static Failure* ThrowRedeclarationError(Isolate* isolate,
1075 const char* type,
1076 Handle<String> name) {
1077 HandleScope scope(isolate);
1078 Handle<Object> type_handle =
1079 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 Handle<Object> args[2] = { type_handle, name };
1081 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1083 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084}
1085
1086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001087RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 HandleScope scope(isolate);
1090 Handle<GlobalObject> global = Handle<GlobalObject>(
1091 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
ager@chromium.org3811b432009-10-28 14:53:37 +00001093 Handle<Context> context = args.at<Context>(0);
1094 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001095 bool is_eval = args.smi_at(2) == 1;
1096 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001097 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
1099 // Compute the property attributes. According to ECMA-262, section
1100 // 13, page 71, the property must be read-only and
1101 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1102 // property as read-only, so we don't either.
1103 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 // Traverse the name/value pairs and set the properties.
1106 int length = pairs->length();
1107 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001110 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
1112 // We have to declare a global const property. To capture we only
1113 // assign to it when evaluating the assignment for "const x =
1114 // <expr>" the initial value is the hole.
1115 bool is_const_property = value->IsTheHole();
1116
1117 if (value->IsUndefined() || is_const_property) {
1118 // Lookup the property in the global object, and don't set the
1119 // value of the variable if the property is already there.
1120 LookupResult lookup;
1121 global->Lookup(*name, &lookup);
1122 if (lookup.IsProperty()) {
1123 // Determine if the property is local by comparing the holder
1124 // against the global object. The information will be used to
1125 // avoid throwing re-declaration errors when declaring
1126 // variables or constants that exist in the prototype chain.
1127 bool is_local = (*global == lookup.holder());
1128 // Get the property attributes and determine if the property is
1129 // read-only.
1130 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1131 bool is_read_only = (attributes & READ_ONLY) != 0;
1132 if (lookup.type() == INTERCEPTOR) {
1133 // If the interceptor says the property is there, we
1134 // just return undefined without overwriting the property.
1135 // Otherwise, we continue to setting the property.
1136 if (attributes != ABSENT) {
1137 // Check if the existing property conflicts with regards to const.
1138 if (is_local && (is_read_only || is_const_property)) {
1139 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 };
1142 // The property already exists without conflicting: Go to
1143 // the next declaration.
1144 continue;
1145 }
1146 // Fall-through and introduce the absent property by using
1147 // SetProperty.
1148 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001149 // For const properties, we treat a callback with this name
1150 // even in the prototype as a conflicting declaration.
1151 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001152 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001153 }
1154 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 if (is_local && (is_read_only || is_const_property)) {
1156 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001157 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 }
1159 // The property already exists without conflicting: Go to
1160 // the next declaration.
1161 continue;
1162 }
1163 }
1164 } else {
1165 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001166 Handle<SharedFunctionInfo> shared =
1167 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1170 context,
1171 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 value = function;
1173 }
1174
1175 LookupResult lookup;
1176 global->LocalLookup(*name, &lookup);
1177
1178 PropertyAttributes attributes = is_const_property
1179 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1180 : base;
1181
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001182 // There's a local property that we need to overwrite because
1183 // we're either declaring a function or there's an interceptor
1184 // that claims the property is absent.
1185 //
1186 // Check for conflicting re-declarations. We cannot have
1187 // conflicting types in case of intercepted properties because
1188 // they are absent.
1189 if (lookup.IsProperty() &&
1190 (lookup.type() != INTERCEPTOR) &&
1191 (lookup.IsReadOnly() || is_const_property)) {
1192 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001196 // Safari does not allow the invocation of callback setters for
1197 // function declarations. To mimic this behavior, we do not allow
1198 // the invocation of setters for function values. This makes a
1199 // difference for global functions with the same names as event
1200 // handlers such as "function onload() {}". Firefox does call the
1201 // onload setter in those case and Safari does not. We follow
1202 // Safari for compatibility.
1203 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001204 // Do not change DONT_DELETE to false from true.
1205 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1206 attributes = static_cast<PropertyAttributes>(
1207 attributes | (lookup.GetAttributes() & DONT_DELETE));
1208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 RETURN_IF_EMPTY_HANDLE(isolate,
1210 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001211 name,
1212 value,
1213 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001215 RETURN_IF_EMPTY_HANDLE(isolate,
1216 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001217 name,
1218 value,
1219 attributes,
1220 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 }
1222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001224 ASSERT(!isolate->has_pending_exception());
1225 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226}
1227
1228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001229RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001231 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
ager@chromium.org7c537e22008-10-16 08:43:32 +00001233 CONVERT_ARG_CHECKED(Context, context, 0);
1234 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001235 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001236 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238
1239 // Declarations are always done in the function context.
1240 context = Handle<Context>(context->fcontext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001241 ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242
1243 int index;
1244 PropertyAttributes attributes;
1245 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001246 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 context->Lookup(name, flags, &index, &attributes);
1248
1249 if (attributes != ABSENT) {
1250 // The name was declared before; check for conflicting
1251 // re-declarations: This is similar to the code in parser.cc in
1252 // the AstBuildingParser::Declare function.
1253 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1254 // Functions are not read-only.
1255 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1256 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 }
1259
1260 // Initialize it if necessary.
1261 if (*initial_value != NULL) {
1262 if (index >= 0) {
1263 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001264 // the function context or the arguments object.
1265 if (holder->IsContext()) {
1266 ASSERT(holder.is_identical_to(context));
1267 if (((attributes & READ_ONLY) == 0) ||
1268 context->get(index)->IsTheHole()) {
1269 context->set(index, *initial_value);
1270 }
1271 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001272 // The holder is an arguments object.
1273 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001274 Handle<Object> result = SetElement(arguments, index, initial_value,
1275 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001276 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278 } else {
1279 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001280 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001281 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001283 SetProperty(context_ext, name, initial_value,
1284 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001289 // The property is not in the function context. It needs to be
1290 // "declared" in the function context's extension context, or in the
1291 // global context.
1292 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001293 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001295 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001296 } else {
1297 // The function context's extension context does not exists - allocate
1298 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001299 context_ext = isolate->factory()->NewJSObject(
1300 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001301 // And store it in the extension slot.
1302 context->set_extension(*context_ext);
1303 }
1304 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
ager@chromium.org7c537e22008-10-16 08:43:32 +00001306 // Declare the property by setting it to the initial value if provided,
1307 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1308 // constant declarations).
1309 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001311 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001312 // Declaring a const context slot is a conflicting declaration if
1313 // there is a callback with that name in a prototype. It is
1314 // allowed to introduce const variables in
1315 // JSContextExtensionObjects. They are treated specially in
1316 // SetProperty and no setters are invoked for those since they are
1317 // not real JSObjects.
1318 if (initial_value->IsTheHole() &&
1319 !context_ext->IsJSContextExtensionObject()) {
1320 LookupResult lookup;
1321 context_ext->Lookup(*name, &lookup);
1322 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001323 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 }
1325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 RETURN_IF_EMPTY_HANDLE(isolate,
1327 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001329 }
1330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332}
1333
1334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001335RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001337 // args[0] == name
1338 // args[1] == strict_mode
1339 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341 // Determine if we need to assign to the variable if it already
1342 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1344 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001349 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
1352 // According to ECMA-262, section 12.2, page 62, the property must
1353 // not be deletable.
1354 PropertyAttributes attributes = DONT_DELETE;
1355
1356 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001357 // there, there is a property with this name in the prototype chain.
1358 // We follow Safari and Firefox behavior and only set the property
1359 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001360 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001361 // Note that objects can have hidden prototypes, so we need to traverse
1362 // the whole chain of hidden prototypes to do a 'local' lookup.
1363 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001365 while (true) {
1366 real_holder->LocalLookup(*name, &lookup);
1367 if (lookup.IsProperty()) {
1368 // Determine if this is a redeclaration of something read-only.
1369 if (lookup.IsReadOnly()) {
1370 // If we found readonly property on one of hidden prototypes,
1371 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001372 if (real_holder != isolate->context()->global()) break;
1373 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001374 }
1375
1376 // Determine if this is a redeclaration of an intercepted read-only
1377 // property and figure out if the property exists at all.
1378 bool found = true;
1379 PropertyType type = lookup.type();
1380 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001382 Handle<JSObject> holder(real_holder);
1383 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1384 real_holder = *holder;
1385 if (intercepted == ABSENT) {
1386 // The interceptor claims the property isn't there. We need to
1387 // make sure to introduce it.
1388 found = false;
1389 } else if ((intercepted & READ_ONLY) != 0) {
1390 // The property is present, but read-only. Since we're trying to
1391 // overwrite it with a variable declaration we must throw a
1392 // re-declaration error. However if we found readonly property
1393 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 if (real_holder != isolate->context()->global()) break;
1395 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001396 }
1397 }
1398
1399 if (found && !assign) {
1400 // The global property is there and we're not assigning any value
1401 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 }
1404
1405 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001407 return real_holder->SetProperty(
1408 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001409 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001410
1411 Object* proto = real_holder->GetPrototype();
1412 if (!proto->IsJSObject())
1413 break;
1414
1415 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1416 break;
1417
1418 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 }
1420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001422 if (assign) {
1423 return global->SetProperty(*name, args[2], attributes, strict_mode);
1424 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426}
1427
1428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001429RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 // All constants are declared with an initial value. The name
1431 // of the constant is the first argument and the initial value
1432 // is the second.
1433 RUNTIME_ASSERT(args.length() == 2);
1434 CONVERT_ARG_CHECKED(String, name, 0);
1435 Handle<Object> value = args.at<Object>(1);
1436
1437 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
1440 // According to ECMA-262, section 12.2, page 62, the property must
1441 // not be deletable. Since it's a const, it must be READ_ONLY too.
1442 PropertyAttributes attributes =
1443 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1444
1445 // Lookup the property locally in the global object. If it isn't
1446 // there, we add the property and take special precautions to always
1447 // add it as a local property even in case of callbacks in the
1448 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001449 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 LookupResult lookup;
1451 global->LocalLookup(*name, &lookup);
1452 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001453 return global->SetLocalPropertyIgnoreAttributes(*name,
1454 *value,
1455 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 }
1457
1458 // Determine if this is a redeclaration of something not
1459 // read-only. In case the result is hidden behind an interceptor we
1460 // need to ask it for the property attributes.
1461 if (!lookup.IsReadOnly()) {
1462 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001463 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 }
1465
1466 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1467
1468 // Throw re-declaration error if the intercepted property is present
1469 // but not read-only.
1470 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
1474 // Restore global object from context (in case of GC) and continue
1475 // with setting the value because the property is either absent or
1476 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 HandleScope handle_scope(isolate);
1478 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001480 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // property through an interceptor and only do it if it's
1482 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 RETURN_IF_EMPTY_HANDLE(isolate,
1485 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001486 name,
1487 value,
1488 attributes,
1489 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 return *value;
1491 }
1492
1493 // Set the value, but only we're assigning the initial value to a
1494 // constant. For now, we determine this by checking if the
1495 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001496 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 PropertyType type = lookup.type();
1498 if (type == FIELD) {
1499 FixedArray* properties = global->properties();
1500 int index = lookup.GetFieldIndex();
1501 if (properties->get(index)->IsTheHole()) {
1502 properties->set(index, *value);
1503 }
1504 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1506 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508 } else {
1509 // Ignore re-initialization of constants that have already been
1510 // assigned a function value.
1511 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1512 }
1513
1514 // Use the set value as the result of the operation.
1515 return *value;
1516}
1517
1518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001519RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 ASSERT(args.length() == 3);
1522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001523 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 ASSERT(!value->IsTheHole());
1525 CONVERT_ARG_CHECKED(Context, context, 1);
1526 Handle<String> name(String::cast(args[2]));
1527
1528 // Initializations are always done in the function context.
1529 context = Handle<Context>(context->fcontext());
1530
1531 int index;
1532 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001533 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001534 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 context->Lookup(name, flags, &index, &attributes);
1536
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001537 // In most situations, the property introduced by the const
1538 // declaration should be present in the context extension object.
1539 // However, because declaration and initialization are separate, the
1540 // property might have been deleted (if it was introduced by eval)
1541 // before we reach the initialization point.
1542 //
1543 // Example:
1544 //
1545 // function f() { eval("delete x; const x;"); }
1546 //
1547 // In that case, the initialization behaves like a normal assignment
1548 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // Property was found in a context.
1551 if (holder->IsContext()) {
1552 // The holder cannot be the function context. If it is, there
1553 // should have been a const redeclaration error when declaring
1554 // the const property.
1555 ASSERT(!holder.is_identical_to(context));
1556 if ((attributes & READ_ONLY) == 0) {
1557 Handle<Context>::cast(holder)->set(index, *value);
1558 }
1559 } else {
1560 // The holder is an arguments object.
1561 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001562 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001563 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001565 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 }
1567 return *value;
1568 }
1569
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001570 // The property could not be found, we introduce it in the global
1571 // context.
1572 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 Handle<JSObject> global = Handle<JSObject>(
1574 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001575 // Strict mode not needed (const disallowed in strict mode).
1576 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001577 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001578 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 return *value;
1580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001582 // The property was present in a context extension object.
1583 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 if (*context_ext == context->extension()) {
1586 // This is the property that was introduced by the const
1587 // declaration. Set it if it hasn't been set before. NOTE: We
1588 // cannot use GetProperty() to get the current value as it
1589 // 'unholes' the value.
1590 LookupResult lookup;
1591 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1592 ASSERT(lookup.IsProperty()); // the property was declared
1593 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1594
1595 PropertyType type = lookup.type();
1596 if (type == FIELD) {
1597 FixedArray* properties = context_ext->properties();
1598 int index = lookup.GetFieldIndex();
1599 if (properties->get(index)->IsTheHole()) {
1600 properties->set(index, *value);
1601 }
1602 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001603 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1604 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001605 }
1606 } else {
1607 // We should not reach here. Any real, named property should be
1608 // either a field or a dictionary slot.
1609 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 }
1611 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001612 // The property was found in a different context extension object.
1613 // Set it if it is not a read-only property.
1614 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001615 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001616 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001617 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001618 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622 return *value;
1623}
1624
1625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001626RUNTIME_FUNCTION(MaybeObject*,
1627 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001629 ASSERT(args.length() == 2);
1630 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001631 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001632 if (object->HasFastProperties()) {
1633 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1634 }
1635 return *object;
1636}
1637
1638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001639RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001641 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001642 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1643 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001644 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001645 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001646 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001647 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001648 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001649 RUNTIME_ASSERT(index >= 0);
1650 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001651 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001652 Handle<Object> result = RegExpImpl::Exec(regexp,
1653 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001654 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001655 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001656 if (result.is_null()) return Failure::Exception();
1657 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658}
1659
1660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001661RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001663 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001664 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001667 Object* new_object;
1668 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001669 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1671 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001672 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001673 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1674 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001675 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1676 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001677 {
1678 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001680 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 }
1683 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001685 array->set_elements(elements);
1686 array->set_length(Smi::FromInt(elements_count));
1687 // Write in-object properties after the length of the array.
1688 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1689 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1690 return array;
1691}
1692
1693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001694RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001695 AssertNoAllocation no_alloc;
1696 ASSERT(args.length() == 5);
1697 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1698 CONVERT_CHECKED(String, source, args[1]);
1699
1700 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001704 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001705
1706 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001708
1709 Map* map = regexp->map();
1710 Object* constructor = map->constructor();
1711 if (constructor->IsJSFunction() &&
1712 JSFunction::cast(constructor)->initial_map() == map) {
1713 // If we still have the original map, set in-object properties directly.
1714 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1715 // TODO(lrn): Consider skipping write barrier on booleans as well.
1716 // Both true and false should be in oldspace at all times.
1717 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1718 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1719 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1720 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1721 Smi::FromInt(0),
1722 SKIP_WRITE_BARRIER);
1723 return regexp;
1724 }
1725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001727 PropertyAttributes final =
1728 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1729 PropertyAttributes writable =
1730 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001734 source,
1735 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001736 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001738 global,
1739 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001740 ASSERT(!result->IsFailure());
1741 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001743 ignoreCase,
1744 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001745 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001747 multiline,
1748 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 ASSERT(!result->IsFailure());
1750 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001752 Smi::FromInt(0),
1753 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001754 ASSERT(!result->IsFailure());
1755 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001756 return regexp;
1757}
1758
1759
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001760RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001762 ASSERT(args.length() == 1);
1763 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1764 // This is necessary to enable fast checks for absence of elements
1765 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001767 return Smi::FromInt(0);
1768}
1769
1770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1772 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001773 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001774 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1776 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1777 Handle<JSFunction> optimized =
1778 isolate->factory()->NewFunction(key,
1779 JS_OBJECT_TYPE,
1780 JSObject::kHeaderSize,
1781 code,
1782 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001784 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001785 return optimized;
1786}
1787
1788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001789RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001791 ASSERT(args.length() == 1);
1792 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1793
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001794 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1795 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1796 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1797 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1798 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1799 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1800 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001801
1802 return *holder;
1803}
1804
1805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001806RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001807 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 Context* global_context =
1809 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001810 return global_context->global()->global_receiver();
1811}
1812
1813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001814RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001815 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 ASSERT(args.length() == 4);
1817 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001818 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819 Handle<String> pattern = args.at<String>(2);
1820 Handle<String> flags = args.at<String>(3);
1821
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001822 // Get the RegExp function from the context in the literals array.
1823 // This is the RegExp function from the context in which the
1824 // function was created. We do not use the RegExp function from the
1825 // current global context because this might be the RegExp function
1826 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001828 Handle<JSFunction>(
1829 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830 // Compute the regular expression literal.
1831 bool has_pending_exception;
1832 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001833 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1834 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 return Failure::Exception();
1838 }
1839 literals->set(index, *regexp);
1840 return *regexp;
1841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
1849 return f->shared()->name();
1850}
1851
1852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001853RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001854 NoHandleAllocation ha;
1855 ASSERT(args.length() == 2);
1856
1857 CONVERT_CHECKED(JSFunction, f, args[0]);
1858 CONVERT_CHECKED(String, name, args[1]);
1859 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001861}
1862
1863
whesse@chromium.org7b260152011-06-20 15:33:18 +00001864RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1865 HandleScope scope(isolate);
1866 ASSERT(args.length() == 1);
1867
1868 CONVERT_CHECKED(JSFunction, fun, args[0]);
1869 fun->shared()->set_bound(true);
1870 return isolate->heap()->undefined_value();
1871}
1872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001873RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001874 NoHandleAllocation ha;
1875 ASSERT(args.length() == 1);
1876
1877 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001878 Object* obj = f->RemovePrototype();
1879 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001881 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001886 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001887 ASSERT(args.length() == 1);
1888
1889 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1891 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892
1893 return *GetScriptWrapper(Handle<Script>::cast(script));
1894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001898 NoHandleAllocation ha;
1899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, f, args[0]);
1902 return f->shared()->GetSourceCode();
1903}
1904
1905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001906RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001907 NoHandleAllocation ha;
1908 ASSERT(args.length() == 1);
1909
1910 CONVERT_CHECKED(JSFunction, fun, args[0]);
1911 int pos = fun->shared()->start_position();
1912 return Smi::FromInt(pos);
1913}
1914
1915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001916RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001917 ASSERT(args.length() == 2);
1918
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001919 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001920 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1921
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001922 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1923
1924 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001925 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001926}
1927
1928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001929RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001930 NoHandleAllocation ha;
1931 ASSERT(args.length() == 2);
1932
1933 CONVERT_CHECKED(JSFunction, fun, args[0]);
1934 CONVERT_CHECKED(String, name, args[1]);
1935 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001936 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001937}
1938
1939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001940RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 NoHandleAllocation ha;
1942 ASSERT(args.length() == 2);
1943
1944 CONVERT_CHECKED(JSFunction, fun, args[0]);
1945 CONVERT_CHECKED(Smi, length, args[1]);
1946 fun->shared()->set_length(length->value());
1947 return length;
1948}
1949
1950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001951RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001952 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 ASSERT(args.length() == 2);
1954
1955 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001956 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001957 Object* obj;
1958 { MaybeObject* maybe_obj =
1959 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1960 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1961 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return args[0]; // return TOS
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1972 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001973}
1974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001976RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 1);
1979
1980 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001981 return f->IsBuiltin() ? isolate->heap()->true_value() :
1982 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001983}
1984
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 ASSERT(args.length() == 2);
1989
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001990 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 Handle<Object> code = args.at<Object>(1);
1992
1993 Handle<Context> context(target->context());
1994
1995 if (!code->IsNull()) {
1996 RUNTIME_ASSERT(code->IsJSFunction());
1997 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001998 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999
2000 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 return Failure::Exception();
2002 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002003 // Since we don't store the source for this we should never
2004 // optimize this.
2005 shared->code()->set_optimizable(false);
2006
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002007 // Set the code, scope info, formal parameter count,
2008 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002009 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002010 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002011 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002012 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002014 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002015 // Set the source code of the target function to undefined.
2016 // SetCode is only used for built-in constructors like String,
2017 // Array, and Object, and some web code
2018 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002020 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002021 // Clear the optimization hints related to the compiled code as these are no
2022 // longer valid when the code is overwritten.
2023 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002024 context = Handle<Context>(fun->context());
2025
2026 // Make sure we get a fresh copy of the literal vector to avoid
2027 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002028 int number_of_literals = fun->NumberOfLiterals();
2029 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002030 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002032 // Insert the object, regexp and array functions in the literals
2033 // array prefix. These are the functions that will be used when
2034 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002035 literals->set(JSFunction::kLiteralGlobalContextIndex,
2036 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002038 // It's okay to skip the write barrier here because the literals
2039 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002040 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002041 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 }
2043
2044 target->set_context(*context);
2045 return *target;
2046}
2047
2048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002051 ASSERT(args.length() == 2);
2052 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002053 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002054 RUNTIME_ASSERT(num >= 0);
2055 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002056 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002057}
2058
2059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002060MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2061 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002062 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002063 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002064 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002065 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002066 }
2067 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002069}
2070
2071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 NoHandleAllocation ha;
2074 ASSERT(args.length() == 2);
2075
2076 CONVERT_CHECKED(String, subject, args[0]);
2077 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002078 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002080 uint32_t i = 0;
2081 if (index->IsSmi()) {
2082 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002083 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002084 i = value;
2085 } else {
2086 ASSERT(index->IsHeapNumber());
2087 double value = HeapNumber::cast(index)->value();
2088 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002089 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002090
2091 // Flatten the string. If someone wants to get a char at an index
2092 // in a cons string, it is likely that more indices will be
2093 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002094 Object* flat;
2095 { MaybeObject* maybe_flat = subject->TryFlatten();
2096 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2097 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002098 subject = String::cast(flat);
2099
2100 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002101 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002102 }
2103
2104 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002105}
2106
2107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002108RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002109 NoHandleAllocation ha;
2110 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002111 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002112}
2113
lrn@chromium.org25156de2010-04-06 13:10:27 +00002114
2115class FixedArrayBuilder {
2116 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002117 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2118 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002119 length_(0) {
2120 // Require a non-zero initial size. Ensures that doubling the size to
2121 // extend the array will work.
2122 ASSERT(initial_capacity > 0);
2123 }
2124
2125 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2126 : array_(backing_store),
2127 length_(0) {
2128 // Require a non-zero initial size. Ensures that doubling the size to
2129 // extend the array will work.
2130 ASSERT(backing_store->length() > 0);
2131 }
2132
2133 bool HasCapacity(int elements) {
2134 int length = array_->length();
2135 int required_length = length_ + elements;
2136 return (length >= required_length);
2137 }
2138
2139 void EnsureCapacity(int elements) {
2140 int length = array_->length();
2141 int required_length = length_ + elements;
2142 if (length < required_length) {
2143 int new_length = length;
2144 do {
2145 new_length *= 2;
2146 } while (new_length < required_length);
2147 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002149 array_->CopyTo(0, *extended_array, 0, length_);
2150 array_ = extended_array;
2151 }
2152 }
2153
2154 void Add(Object* value) {
2155 ASSERT(length_ < capacity());
2156 array_->set(length_, value);
2157 length_++;
2158 }
2159
2160 void Add(Smi* value) {
2161 ASSERT(length_ < capacity());
2162 array_->set(length_, value);
2163 length_++;
2164 }
2165
2166 Handle<FixedArray> array() {
2167 return array_;
2168 }
2169
2170 int length() {
2171 return length_;
2172 }
2173
2174 int capacity() {
2175 return array_->length();
2176 }
2177
2178 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002180 result_array->set_length(Smi::FromInt(length_));
2181 return result_array;
2182 }
2183
2184 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2185 target_array->set_elements(*array_);
2186 target_array->set_length(Smi::FromInt(length_));
2187 return target_array;
2188 }
2189
2190 private:
2191 Handle<FixedArray> array_;
2192 int length_;
2193};
2194
2195
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002197const int kStringBuilderConcatHelperLengthBits = 11;
2198const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002199
2200template <typename schar>
2201static inline void StringBuilderConcatHelper(String*,
2202 schar*,
2203 FixedArray*,
2204 int);
2205
lrn@chromium.org25156de2010-04-06 13:10:27 +00002206typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2207 StringBuilderSubstringLength;
2208typedef BitField<int,
2209 kStringBuilderConcatHelperLengthBits,
2210 kStringBuilderConcatHelperPositionBits>
2211 StringBuilderSubstringPosition;
2212
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002213
2214class ReplacementStringBuilder {
2215 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 ReplacementStringBuilder(Heap* heap,
2217 Handle<String> subject,
2218 int estimated_part_count)
2219 : heap_(heap),
2220 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002221 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002222 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002223 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002224 // Require a non-zero initial size. Ensures that doubling the size to
2225 // extend the array will work.
2226 ASSERT(estimated_part_count > 0);
2227 }
2228
lrn@chromium.org25156de2010-04-06 13:10:27 +00002229 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2230 int from,
2231 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002232 ASSERT(from >= 0);
2233 int length = to - from;
2234 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 if (StringBuilderSubstringLength::is_valid(length) &&
2236 StringBuilderSubstringPosition::is_valid(from)) {
2237 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2238 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002239 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002240 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002241 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 builder->Add(Smi::FromInt(-length));
2243 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002245 }
2246
2247
2248 void EnsureCapacity(int elements) {
2249 array_builder_.EnsureCapacity(elements);
2250 }
2251
2252
2253 void AddSubjectSlice(int from, int to) {
2254 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002255 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 }
2257
2258
2259 void AddString(Handle<String> string) {
2260 int length = string->length();
2261 ASSERT(length > 0);
2262 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002263 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002264 is_ascii_ = false;
2265 }
2266 IncrementCharacterCount(length);
2267 }
2268
2269
2270 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002271 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 }
2274
2275 Handle<String> joined_string;
2276 if (is_ascii_) {
2277 joined_string = NewRawAsciiString(character_count_);
2278 AssertNoAllocation no_alloc;
2279 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2280 char* char_buffer = seq->GetChars();
2281 StringBuilderConcatHelper(*subject_,
2282 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 *array_builder_.array(),
2284 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 } else {
2286 // Non-ASCII.
2287 joined_string = NewRawTwoByteString(character_count_);
2288 AssertNoAllocation no_alloc;
2289 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2290 uc16* char_buffer = seq->GetChars();
2291 StringBuilderConcatHelper(*subject_,
2292 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002293 *array_builder_.array(),
2294 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002295 }
2296 return joined_string;
2297 }
2298
2299
2300 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002301 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002302 V8::FatalProcessOutOfMemory("String.replace result too large.");
2303 }
2304 character_count_ += by;
2305 }
2306
lrn@chromium.org25156de2010-04-06 13:10:27 +00002307 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002308 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002310
lrn@chromium.org25156de2010-04-06 13:10:27 +00002311 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002312 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002313 CALL_HEAP_FUNCTION(heap_->isolate(),
2314 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002315 }
2316
2317
2318 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 CALL_HEAP_FUNCTION(heap_->isolate(),
2320 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002321 }
2322
2323
2324 void AddElement(Object* element) {
2325 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002326 ASSERT(array_builder_.capacity() > array_builder_.length());
2327 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002328 }
2329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002330 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002331 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002332 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002333 int character_count_;
2334 bool is_ascii_;
2335};
2336
2337
2338class CompiledReplacement {
2339 public:
2340 CompiledReplacement()
2341 : parts_(1), replacement_substrings_(0) {}
2342
2343 void Compile(Handle<String> replacement,
2344 int capture_count,
2345 int subject_length);
2346
2347 void Apply(ReplacementStringBuilder* builder,
2348 int match_from,
2349 int match_to,
2350 Handle<JSArray> last_match_info);
2351
2352 // Number of distinct parts of the replacement pattern.
2353 int parts() {
2354 return parts_.length();
2355 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002356
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002357 private:
2358 enum PartType {
2359 SUBJECT_PREFIX = 1,
2360 SUBJECT_SUFFIX,
2361 SUBJECT_CAPTURE,
2362 REPLACEMENT_SUBSTRING,
2363 REPLACEMENT_STRING,
2364
2365 NUMBER_OF_PART_TYPES
2366 };
2367
2368 struct ReplacementPart {
2369 static inline ReplacementPart SubjectMatch() {
2370 return ReplacementPart(SUBJECT_CAPTURE, 0);
2371 }
2372 static inline ReplacementPart SubjectCapture(int capture_index) {
2373 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2374 }
2375 static inline ReplacementPart SubjectPrefix() {
2376 return ReplacementPart(SUBJECT_PREFIX, 0);
2377 }
2378 static inline ReplacementPart SubjectSuffix(int subject_length) {
2379 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2380 }
2381 static inline ReplacementPart ReplacementString() {
2382 return ReplacementPart(REPLACEMENT_STRING, 0);
2383 }
2384 static inline ReplacementPart ReplacementSubString(int from, int to) {
2385 ASSERT(from >= 0);
2386 ASSERT(to > from);
2387 return ReplacementPart(-from, to);
2388 }
2389
2390 // If tag <= 0 then it is the negation of a start index of a substring of
2391 // the replacement pattern, otherwise it's a value from PartType.
2392 ReplacementPart(int tag, int data)
2393 : tag(tag), data(data) {
2394 // Must be non-positive or a PartType value.
2395 ASSERT(tag < NUMBER_OF_PART_TYPES);
2396 }
2397 // Either a value of PartType or a non-positive number that is
2398 // the negation of an index into the replacement string.
2399 int tag;
2400 // The data value's interpretation depends on the value of tag:
2401 // tag == SUBJECT_PREFIX ||
2402 // tag == SUBJECT_SUFFIX: data is unused.
2403 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2404 // tag == REPLACEMENT_SUBSTRING ||
2405 // tag == REPLACEMENT_STRING: data is index into array of substrings
2406 // of the replacement string.
2407 // tag <= 0: Temporary representation of the substring of the replacement
2408 // string ranging over -tag .. data.
2409 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2410 // substring objects.
2411 int data;
2412 };
2413
2414 template<typename Char>
2415 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2416 Vector<Char> characters,
2417 int capture_count,
2418 int subject_length) {
2419 int length = characters.length();
2420 int last = 0;
2421 for (int i = 0; i < length; i++) {
2422 Char c = characters[i];
2423 if (c == '$') {
2424 int next_index = i + 1;
2425 if (next_index == length) { // No next character!
2426 break;
2427 }
2428 Char c2 = characters[next_index];
2429 switch (c2) {
2430 case '$':
2431 if (i > last) {
2432 // There is a substring before. Include the first "$".
2433 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2434 last = next_index + 1; // Continue after the second "$".
2435 } else {
2436 // Let the next substring start with the second "$".
2437 last = next_index;
2438 }
2439 i = next_index;
2440 break;
2441 case '`':
2442 if (i > last) {
2443 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2444 }
2445 parts->Add(ReplacementPart::SubjectPrefix());
2446 i = next_index;
2447 last = i + 1;
2448 break;
2449 case '\'':
2450 if (i > last) {
2451 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2452 }
2453 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2454 i = next_index;
2455 last = i + 1;
2456 break;
2457 case '&':
2458 if (i > last) {
2459 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2460 }
2461 parts->Add(ReplacementPart::SubjectMatch());
2462 i = next_index;
2463 last = i + 1;
2464 break;
2465 case '0':
2466 case '1':
2467 case '2':
2468 case '3':
2469 case '4':
2470 case '5':
2471 case '6':
2472 case '7':
2473 case '8':
2474 case '9': {
2475 int capture_ref = c2 - '0';
2476 if (capture_ref > capture_count) {
2477 i = next_index;
2478 continue;
2479 }
2480 int second_digit_index = next_index + 1;
2481 if (second_digit_index < length) {
2482 // Peek ahead to see if we have two digits.
2483 Char c3 = characters[second_digit_index];
2484 if ('0' <= c3 && c3 <= '9') { // Double digits.
2485 int double_digit_ref = capture_ref * 10 + c3 - '0';
2486 if (double_digit_ref <= capture_count) {
2487 next_index = second_digit_index;
2488 capture_ref = double_digit_ref;
2489 }
2490 }
2491 }
2492 if (capture_ref > 0) {
2493 if (i > last) {
2494 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2495 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002496 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2498 last = next_index + 1;
2499 }
2500 i = next_index;
2501 break;
2502 }
2503 default:
2504 i = next_index;
2505 break;
2506 }
2507 }
2508 }
2509 if (length > last) {
2510 if (last == 0) {
2511 parts->Add(ReplacementPart::ReplacementString());
2512 } else {
2513 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2514 }
2515 }
2516 }
2517
2518 ZoneList<ReplacementPart> parts_;
2519 ZoneList<Handle<String> > replacement_substrings_;
2520};
2521
2522
2523void CompiledReplacement::Compile(Handle<String> replacement,
2524 int capture_count,
2525 int subject_length) {
2526 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002527 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 AssertNoAllocation no_alloc;
2529 ParseReplacementPattern(&parts_,
2530 replacement->ToAsciiVector(),
2531 capture_count,
2532 subject_length);
2533 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002534 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535 AssertNoAllocation no_alloc;
2536
2537 ParseReplacementPattern(&parts_,
2538 replacement->ToUC16Vector(),
2539 capture_count,
2540 subject_length);
2541 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002542 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002543 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002544 int substring_index = 0;
2545 for (int i = 0, n = parts_.length(); i < n; i++) {
2546 int tag = parts_[i].tag;
2547 if (tag <= 0) { // A replacement string slice.
2548 int from = -tag;
2549 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002550 replacement_substrings_.Add(
2551 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002552 parts_[i].tag = REPLACEMENT_SUBSTRING;
2553 parts_[i].data = substring_index;
2554 substring_index++;
2555 } else if (tag == REPLACEMENT_STRING) {
2556 replacement_substrings_.Add(replacement);
2557 parts_[i].data = substring_index;
2558 substring_index++;
2559 }
2560 }
2561}
2562
2563
2564void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2565 int match_from,
2566 int match_to,
2567 Handle<JSArray> last_match_info) {
2568 for (int i = 0, n = parts_.length(); i < n; i++) {
2569 ReplacementPart part = parts_[i];
2570 switch (part.tag) {
2571 case SUBJECT_PREFIX:
2572 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2573 break;
2574 case SUBJECT_SUFFIX: {
2575 int subject_length = part.data;
2576 if (match_to < subject_length) {
2577 builder->AddSubjectSlice(match_to, subject_length);
2578 }
2579 break;
2580 }
2581 case SUBJECT_CAPTURE: {
2582 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002583 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002584 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2585 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2586 if (from >= 0 && to > from) {
2587 builder->AddSubjectSlice(from, to);
2588 }
2589 break;
2590 }
2591 case REPLACEMENT_SUBSTRING:
2592 case REPLACEMENT_STRING:
2593 builder->AddString(replacement_substrings_[part.data]);
2594 break;
2595 default:
2596 UNREACHABLE();
2597 }
2598 }
2599}
2600
2601
2602
lrn@chromium.org303ada72010-10-27 09:33:13 +00002603MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002604 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002605 String* subject,
2606 JSRegExp* regexp,
2607 String* replacement,
2608 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002609 ASSERT(subject->IsFlat());
2610 ASSERT(replacement->IsFlat());
2611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002612 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002613
2614 int length = subject->length();
2615 Handle<String> subject_handle(subject);
2616 Handle<JSRegExp> regexp_handle(regexp);
2617 Handle<String> replacement_handle(replacement);
2618 Handle<JSArray> last_match_info_handle(last_match_info);
2619 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2620 subject_handle,
2621 0,
2622 last_match_info_handle);
2623 if (match.is_null()) {
2624 return Failure::Exception();
2625 }
2626 if (match->IsNull()) {
2627 return *subject_handle;
2628 }
2629
2630 int capture_count = regexp_handle->CaptureCount();
2631
2632 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002633 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002634 CompiledReplacement compiled_replacement;
2635 compiled_replacement.Compile(replacement_handle,
2636 capture_count,
2637 length);
2638
2639 bool is_global = regexp_handle->GetFlags().is_global();
2640
2641 // Guessing the number of parts that the final result string is built
2642 // from. Global regexps can match any number of times, so we guess
2643 // conservatively.
2644 int expected_parts =
2645 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002646 ReplacementStringBuilder builder(isolate->heap(),
2647 subject_handle,
2648 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649
2650 // Index of end of last match.
2651 int prev = 0;
2652
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002653 // Number of parts added by compiled replacement plus preceeding
2654 // string and possibly suffix after last match. It is possible for
2655 // all components to use two elements when encoded as two smis.
2656 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002657 bool matched = true;
2658 do {
2659 ASSERT(last_match_info_handle->HasFastElements());
2660 // Increase the capacity of the builder before entering local handle-scope,
2661 // so its internal buffer can safely allocate a new handle if it grows.
2662 builder.EnsureCapacity(parts_added_per_loop);
2663
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002664 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 int start, end;
2666 {
2667 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002668 FixedArray* match_info_array =
2669 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670
2671 ASSERT_EQ(capture_count * 2 + 2,
2672 RegExpImpl::GetLastCaptureCount(match_info_array));
2673 start = RegExpImpl::GetCapture(match_info_array, 0);
2674 end = RegExpImpl::GetCapture(match_info_array, 1);
2675 }
2676
2677 if (prev < start) {
2678 builder.AddSubjectSlice(prev, start);
2679 }
2680 compiled_replacement.Apply(&builder,
2681 start,
2682 end,
2683 last_match_info_handle);
2684 prev = end;
2685
2686 // Only continue checking for global regexps.
2687 if (!is_global) break;
2688
2689 // Continue from where the match ended, unless it was an empty match.
2690 int next = end;
2691 if (start == end) {
2692 next = end + 1;
2693 if (next > length) break;
2694 }
2695
2696 match = RegExpImpl::Exec(regexp_handle,
2697 subject_handle,
2698 next,
2699 last_match_info_handle);
2700 if (match.is_null()) {
2701 return Failure::Exception();
2702 }
2703 matched = !match->IsNull();
2704 } while (matched);
2705
2706 if (prev < length) {
2707 builder.AddSubjectSlice(prev, length);
2708 }
2709
2710 return *(builder.ToString());
2711}
2712
2713
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002714template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002715MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002716 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002717 String* subject,
2718 JSRegExp* regexp,
2719 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 ASSERT(subject->IsFlat());
2721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002722 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002723
2724 Handle<String> subject_handle(subject);
2725 Handle<JSRegExp> regexp_handle(regexp);
2726 Handle<JSArray> last_match_info_handle(last_match_info);
2727 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2728 subject_handle,
2729 0,
2730 last_match_info_handle);
2731 if (match.is_null()) return Failure::Exception();
2732 if (match->IsNull()) return *subject_handle;
2733
2734 ASSERT(last_match_info_handle->HasFastElements());
2735
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002736 int start, end;
2737 {
2738 AssertNoAllocation match_info_array_is_not_in_a_handle;
2739 FixedArray* match_info_array =
2740 FixedArray::cast(last_match_info_handle->elements());
2741
2742 start = RegExpImpl::GetCapture(match_info_array, 0);
2743 end = RegExpImpl::GetCapture(match_info_array, 1);
2744 }
2745
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002746 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002747 int new_length = length - (end - start);
2748 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002749 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002750 }
2751 Handle<ResultSeqString> answer;
2752 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002753 answer = Handle<ResultSeqString>::cast(
2754 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002755 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002756 answer = Handle<ResultSeqString>::cast(
2757 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002758 }
2759
2760 // If the regexp isn't global, only match once.
2761 if (!regexp_handle->GetFlags().is_global()) {
2762 if (start > 0) {
2763 String::WriteToFlat(*subject_handle,
2764 answer->GetChars(),
2765 0,
2766 start);
2767 }
2768 if (end < length) {
2769 String::WriteToFlat(*subject_handle,
2770 answer->GetChars() + start,
2771 end,
2772 length);
2773 }
2774 return *answer;
2775 }
2776
2777 int prev = 0; // Index of end of last match.
2778 int next = 0; // Start of next search (prev unless last match was empty).
2779 int position = 0;
2780
2781 do {
2782 if (prev < start) {
2783 // Add substring subject[prev;start] to answer string.
2784 String::WriteToFlat(*subject_handle,
2785 answer->GetChars() + position,
2786 prev,
2787 start);
2788 position += start - prev;
2789 }
2790 prev = end;
2791 next = end;
2792 // Continue from where the match ended, unless it was an empty match.
2793 if (start == end) {
2794 next++;
2795 if (next > length) break;
2796 }
2797 match = RegExpImpl::Exec(regexp_handle,
2798 subject_handle,
2799 next,
2800 last_match_info_handle);
2801 if (match.is_null()) return Failure::Exception();
2802 if (match->IsNull()) break;
2803
2804 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002805 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002806 {
2807 AssertNoAllocation match_info_array_is_not_in_a_handle;
2808 FixedArray* match_info_array =
2809 FixedArray::cast(last_match_info_handle->elements());
2810 start = RegExpImpl::GetCapture(match_info_array, 0);
2811 end = RegExpImpl::GetCapture(match_info_array, 1);
2812 }
2813 } while (true);
2814
2815 if (prev < length) {
2816 // Add substring subject[prev;length] to answer string.
2817 String::WriteToFlat(*subject_handle,
2818 answer->GetChars() + position,
2819 prev,
2820 length);
2821 position += length - prev;
2822 }
2823
2824 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002825 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002826 }
2827
2828 // Shorten string and fill
2829 int string_size = ResultSeqString::SizeFor(position);
2830 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2831 int delta = allocated_string_size - string_size;
2832
2833 answer->set_length(position);
2834 if (delta == 0) return *answer;
2835
2836 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002837 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002838
2839 return *answer;
2840}
2841
2842
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002843RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002844 ASSERT(args.length() == 4);
2845
2846 CONVERT_CHECKED(String, subject, args[0]);
2847 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002848 Object* flat_subject;
2849 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2850 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2851 return maybe_flat_subject;
2852 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002853 }
2854 subject = String::cast(flat_subject);
2855 }
2856
2857 CONVERT_CHECKED(String, replacement, args[2]);
2858 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002859 Object* flat_replacement;
2860 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2861 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2862 return maybe_flat_replacement;
2863 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002864 }
2865 replacement = String::cast(flat_replacement);
2866 }
2867
2868 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2869 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2870
2871 ASSERT(last_match_info->HasFastElements());
2872
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002873 if (replacement->length() == 0) {
2874 if (subject->HasOnlyAsciiChars()) {
2875 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002876 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002877 } else {
2878 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002880 }
2881 }
2882
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002883 return StringReplaceRegExpWithString(isolate,
2884 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002885 regexp,
2886 replacement,
2887 last_match_info);
2888}
2889
2890
ager@chromium.org7c537e22008-10-16 08:43:32 +00002891// Perform string match of pattern on subject, starting at start index.
2892// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002893// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002894int Runtime::StringMatch(Isolate* isolate,
2895 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002896 Handle<String> pat,
2897 int start_index) {
2898 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002899 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002900
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002901 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002902 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002903
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002904 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002905 if (start_index + pattern_length > subject_length) return -1;
2906
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002907 if (!sub->IsFlat()) FlattenString(sub);
2908 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002909
ager@chromium.org7c537e22008-10-16 08:43:32 +00002910 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002911 // Extract flattened substrings of cons strings before determining asciiness.
2912 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002913 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002915 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002916
ager@chromium.org7c537e22008-10-16 08:43:32 +00002917 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002918 if (seq_pat->IsAsciiRepresentation()) {
2919 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2920 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002921 return SearchString(isolate,
2922 seq_sub->ToAsciiVector(),
2923 pat_vector,
2924 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002925 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 return SearchString(isolate,
2927 seq_sub->ToUC16Vector(),
2928 pat_vector,
2929 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002930 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002931 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2932 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 return SearchString(isolate,
2934 seq_sub->ToAsciiVector(),
2935 pat_vector,
2936 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002937 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002938 return SearchString(isolate,
2939 seq_sub->ToUC16Vector(),
2940 pat_vector,
2941 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002942}
2943
2944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002945RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002946 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002947 ASSERT(args.length() == 3);
2948
ager@chromium.org7c537e22008-10-16 08:43:32 +00002949 CONVERT_ARG_CHECKED(String, sub, 0);
2950 CONVERT_ARG_CHECKED(String, pat, 1);
2951
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002952 Object* index = args[2];
2953 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002954 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002955
ager@chromium.org870a0b62008-11-04 11:43:05 +00002956 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 int position =
2958 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002959 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002960}
2961
2962
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002963template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002964static int StringMatchBackwards(Vector<const schar> subject,
2965 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002966 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002967 int pattern_length = pattern.length();
2968 ASSERT(pattern_length >= 1);
2969 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002970
2971 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002972 for (int i = 0; i < pattern_length; i++) {
2973 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002974 if (c > String::kMaxAsciiCharCode) {
2975 return -1;
2976 }
2977 }
2978 }
2979
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002980 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002982 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002983 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002984 while (j < pattern_length) {
2985 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 break;
2987 }
2988 j++;
2989 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002990 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991 return i;
2992 }
2993 }
2994 return -1;
2995}
2996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002997RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999 ASSERT(args.length() == 3);
3000
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003001 CONVERT_ARG_CHECKED(String, sub, 0);
3002 CONVERT_ARG_CHECKED(String, pat, 1);
3003
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003004 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003005 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003006 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003007
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003008 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003009 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003011 if (start_index + pat_length > sub_length) {
3012 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003013 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003014
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003015 if (pat_length == 0) {
3016 return Smi::FromInt(start_index);
3017 }
3018
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003019 if (!sub->IsFlat()) FlattenString(sub);
3020 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003021
3022 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3023
3024 int position = -1;
3025
3026 if (pat->IsAsciiRepresentation()) {
3027 Vector<const char> pat_vector = pat->ToAsciiVector();
3028 if (sub->IsAsciiRepresentation()) {
3029 position = StringMatchBackwards(sub->ToAsciiVector(),
3030 pat_vector,
3031 start_index);
3032 } else {
3033 position = StringMatchBackwards(sub->ToUC16Vector(),
3034 pat_vector,
3035 start_index);
3036 }
3037 } else {
3038 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3039 if (sub->IsAsciiRepresentation()) {
3040 position = StringMatchBackwards(sub->ToAsciiVector(),
3041 pat_vector,
3042 start_index);
3043 } else {
3044 position = StringMatchBackwards(sub->ToUC16Vector(),
3045 pat_vector,
3046 start_index);
3047 }
3048 }
3049
3050 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003051}
3052
3053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003054RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003055 NoHandleAllocation ha;
3056 ASSERT(args.length() == 2);
3057
3058 CONVERT_CHECKED(String, str1, args[0]);
3059 CONVERT_CHECKED(String, str2, args[1]);
3060
3061 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003062 int str1_length = str1->length();
3063 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003064
3065 // Decide trivial cases without flattening.
3066 if (str1_length == 0) {
3067 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3068 return Smi::FromInt(-str2_length);
3069 } else {
3070 if (str2_length == 0) return Smi::FromInt(str1_length);
3071 }
3072
3073 int end = str1_length < str2_length ? str1_length : str2_length;
3074
3075 // No need to flatten if we are going to find the answer on the first
3076 // character. At this point we know there is at least one character
3077 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003078 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079 if (d != 0) return Smi::FromInt(d);
3080
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003081 str1->TryFlatten();
3082 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003083
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 StringInputBuffer& buf1 =
3085 *isolate->runtime_state()->string_locale_compare_buf1();
3086 StringInputBuffer& buf2 =
3087 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003088
3089 buf1.Reset(str1);
3090 buf2.Reset(str2);
3091
3092 for (int i = 0; i < end; i++) {
3093 uint16_t char1 = buf1.GetNext();
3094 uint16_t char2 = buf2.GetNext();
3095 if (char1 != char2) return Smi::FromInt(char1 - char2);
3096 }
3097
3098 return Smi::FromInt(str1_length - str2_length);
3099}
3100
3101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003102RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103 NoHandleAllocation ha;
3104 ASSERT(args.length() == 3);
3105
3106 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003107 int start, end;
3108 // We have a fast integer-only case here to avoid a conversion to double in
3109 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003110 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3111 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3112 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3113 start = from_number;
3114 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003115 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003116 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3117 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003118 start = FastD2I(from_number);
3119 end = FastD2I(to_number);
3120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121 RUNTIME_ASSERT(end >= start);
3122 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003123 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003124 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003125 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126}
3127
3128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003129RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003130 ASSERT_EQ(3, args.length());
3131
3132 CONVERT_ARG_CHECKED(String, subject, 0);
3133 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3134 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3135 HandleScope handles;
3136
3137 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3138
3139 if (match.is_null()) {
3140 return Failure::Exception();
3141 }
3142 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003143 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
3145 int length = subject->length();
3146
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003147 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003148 ZoneList<int> offsets(8);
3149 do {
3150 int start;
3151 int end;
3152 {
3153 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003154 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003155 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3156 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3157 }
3158 offsets.Add(start);
3159 offsets.Add(end);
3160 int index = start < end ? end : end + 1;
3161 if (index > length) break;
3162 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3163 if (match.is_null()) {
3164 return Failure::Exception();
3165 }
3166 } while (!match->IsNull());
3167 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003168 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003169 for (int i = 0; i < matches ; i++) {
3170 int from = offsets.at(i * 2);
3171 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003173 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003174 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003175 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003176 result->set_length(Smi::FromInt(matches));
3177 return *result;
3178}
3179
3180
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181// Two smis before and after the match, for very long strings.
3182const int kMaxBuilderEntriesPerRegExpMatch = 5;
3183
3184
3185static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3186 Handle<JSArray> last_match_info,
3187 int match_start,
3188 int match_end) {
3189 // Fill last_match_info with a single capture.
3190 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3191 AssertNoAllocation no_gc;
3192 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3193 RegExpImpl::SetLastCaptureCount(elements, 2);
3194 RegExpImpl::SetLastInput(elements, *subject);
3195 RegExpImpl::SetLastSubject(elements, *subject);
3196 RegExpImpl::SetCapture(elements, 0, match_start);
3197 RegExpImpl::SetCapture(elements, 1, match_end);
3198}
3199
3200
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003201template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003202static bool SearchStringMultiple(Isolate* isolate,
3203 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204 Vector<const PatternChar> pattern,
3205 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003206 FixedArrayBuilder* builder,
3207 int* match_pos) {
3208 int pos = *match_pos;
3209 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003210 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003212 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003213 while (pos <= max_search_start) {
3214 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3215 *match_pos = pos;
3216 return false;
3217 }
3218 // Position of end of previous match.
3219 int match_end = pos + pattern_length;
3220 int new_pos = search.Search(subject, match_end);
3221 if (new_pos >= 0) {
3222 // A match.
3223 if (new_pos > match_end) {
3224 ReplacementStringBuilder::AddSubjectSlice(builder,
3225 match_end,
3226 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003227 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003228 pos = new_pos;
3229 builder->Add(pattern_string);
3230 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003231 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003232 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003233 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003234
lrn@chromium.org25156de2010-04-06 13:10:27 +00003235 if (pos < max_search_start) {
3236 ReplacementStringBuilder::AddSubjectSlice(builder,
3237 pos + pattern_length,
3238 subject_length);
3239 }
3240 *match_pos = pos;
3241 return true;
3242}
3243
3244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245static bool SearchStringMultiple(Isolate* isolate,
3246 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003247 Handle<String> pattern,
3248 Handle<JSArray> last_match_info,
3249 FixedArrayBuilder* builder) {
3250 ASSERT(subject->IsFlat());
3251 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252
3253 // Treating as if a previous match was before first character.
3254 int match_pos = -pattern->length();
3255
3256 for (;;) { // Break when search complete.
3257 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3258 AssertNoAllocation no_gc;
3259 if (subject->IsAsciiRepresentation()) {
3260 Vector<const char> subject_vector = subject->ToAsciiVector();
3261 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003262 if (SearchStringMultiple(isolate,
3263 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003264 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003265 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003266 builder,
3267 &match_pos)) break;
3268 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003269 if (SearchStringMultiple(isolate,
3270 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003271 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003272 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003273 builder,
3274 &match_pos)) break;
3275 }
3276 } else {
3277 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3278 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 if (SearchStringMultiple(isolate,
3280 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003281 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003282 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003283 builder,
3284 &match_pos)) break;
3285 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 if (SearchStringMultiple(isolate,
3287 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003288 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003289 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003290 builder,
3291 &match_pos)) break;
3292 }
3293 }
3294 }
3295
3296 if (match_pos >= 0) {
3297 SetLastMatchInfoNoCaptures(subject,
3298 last_match_info,
3299 match_pos,
3300 match_pos + pattern->length());
3301 return true;
3302 }
3303 return false; // No matches at all.
3304}
3305
3306
3307static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003308 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003309 Handle<String> subject,
3310 Handle<JSRegExp> regexp,
3311 Handle<JSArray> last_match_array,
3312 FixedArrayBuilder* builder) {
3313 ASSERT(subject->IsFlat());
3314 int match_start = -1;
3315 int match_end = 0;
3316 int pos = 0;
3317 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3318 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3319
3320 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003321 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322 int subject_length = subject->length();
3323
3324 for (;;) { // Break on failure, return on exception.
3325 RegExpImpl::IrregexpResult result =
3326 RegExpImpl::IrregexpExecOnce(regexp,
3327 subject,
3328 pos,
3329 register_vector);
3330 if (result == RegExpImpl::RE_SUCCESS) {
3331 match_start = register_vector[0];
3332 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3333 if (match_end < match_start) {
3334 ReplacementStringBuilder::AddSubjectSlice(builder,
3335 match_end,
3336 match_start);
3337 }
3338 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003339 HandleScope loop_scope(isolate);
3340 builder->Add(*isolate->factory()->NewSubString(subject,
3341 match_start,
3342 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003343 if (match_start != match_end) {
3344 pos = match_end;
3345 } else {
3346 pos = match_end + 1;
3347 if (pos > subject_length) break;
3348 }
3349 } else if (result == RegExpImpl::RE_FAILURE) {
3350 break;
3351 } else {
3352 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3353 return result;
3354 }
3355 }
3356
3357 if (match_start >= 0) {
3358 if (match_end < subject_length) {
3359 ReplacementStringBuilder::AddSubjectSlice(builder,
3360 match_end,
3361 subject_length);
3362 }
3363 SetLastMatchInfoNoCaptures(subject,
3364 last_match_array,
3365 match_start,
3366 match_end);
3367 return RegExpImpl::RE_SUCCESS;
3368 } else {
3369 return RegExpImpl::RE_FAILURE; // No matches at all.
3370 }
3371}
3372
3373
3374static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003376 Handle<String> subject,
3377 Handle<JSRegExp> regexp,
3378 Handle<JSArray> last_match_array,
3379 FixedArrayBuilder* builder) {
3380
3381 ASSERT(subject->IsFlat());
3382 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3383 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3384
3385 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003386 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003387
3388 RegExpImpl::IrregexpResult result =
3389 RegExpImpl::IrregexpExecOnce(regexp,
3390 subject,
3391 0,
3392 register_vector);
3393
3394 int capture_count = regexp->CaptureCount();
3395 int subject_length = subject->length();
3396
3397 // Position to search from.
3398 int pos = 0;
3399 // End of previous match. Differs from pos if match was empty.
3400 int match_end = 0;
3401 if (result == RegExpImpl::RE_SUCCESS) {
3402 // Need to keep a copy of the previous match for creating last_match_info
3403 // at the end, so we have two vectors that we swap between.
3404 OffsetsVector registers2(required_registers);
3405 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3406
3407 do {
3408 int match_start = register_vector[0];
3409 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3410 if (match_end < match_start) {
3411 ReplacementStringBuilder::AddSubjectSlice(builder,
3412 match_end,
3413 match_start);
3414 }
3415 match_end = register_vector[1];
3416
3417 {
3418 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003419 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 // Arguments array to replace function is match, captures, index and
3421 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003422 Handle<FixedArray> elements =
3423 isolate->factory()->NewFixedArray(3 + capture_count);
3424 Handle<String> match = isolate->factory()->NewSubString(subject,
3425 match_start,
3426 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003427 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003428 for (int i = 1; i <= capture_count; i++) {
3429 int start = register_vector[i * 2];
3430 if (start >= 0) {
3431 int end = register_vector[i * 2 + 1];
3432 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003433 Handle<String> substring = isolate->factory()->NewSubString(subject,
3434 start,
3435 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003436 elements->set(i, *substring);
3437 } else {
3438 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003439 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003440 }
3441 }
3442 elements->set(capture_count + 1, Smi::FromInt(match_start));
3443 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003444 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003445 }
3446 // Swap register vectors, so the last successful match is in
3447 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003448 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003449 prev_register_vector = register_vector;
3450 register_vector = tmp;
3451
3452 if (match_end > match_start) {
3453 pos = match_end;
3454 } else {
3455 pos = match_end + 1;
3456 if (pos > subject_length) {
3457 break;
3458 }
3459 }
3460
3461 result = RegExpImpl::IrregexpExecOnce(regexp,
3462 subject,
3463 pos,
3464 register_vector);
3465 } while (result == RegExpImpl::RE_SUCCESS);
3466
3467 if (result != RegExpImpl::RE_EXCEPTION) {
3468 // Finished matching, with at least one match.
3469 if (match_end < subject_length) {
3470 ReplacementStringBuilder::AddSubjectSlice(builder,
3471 match_end,
3472 subject_length);
3473 }
3474
3475 int last_match_capture_count = (capture_count + 1) * 2;
3476 int last_match_array_size =
3477 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3478 last_match_array->EnsureSize(last_match_array_size);
3479 AssertNoAllocation no_gc;
3480 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3481 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3482 RegExpImpl::SetLastSubject(elements, *subject);
3483 RegExpImpl::SetLastInput(elements, *subject);
3484 for (int i = 0; i < last_match_capture_count; i++) {
3485 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3486 }
3487 return RegExpImpl::RE_SUCCESS;
3488 }
3489 }
3490 // No matches at all, return failure or exception result directly.
3491 return result;
3492}
3493
3494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003495RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003496 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003497 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003498
3499 CONVERT_ARG_CHECKED(String, subject, 1);
3500 if (!subject->IsFlat()) { FlattenString(subject); }
3501 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3502 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3503 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3504
3505 ASSERT(last_match_info->HasFastElements());
3506 ASSERT(regexp->GetFlags().is_global());
3507 Handle<FixedArray> result_elements;
3508 if (result_array->HasFastElements()) {
3509 result_elements =
3510 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3511 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003513 }
3514 FixedArrayBuilder builder(result_elements);
3515
3516 if (regexp->TypeTag() == JSRegExp::ATOM) {
3517 Handle<String> pattern(
3518 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003519 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003520 if (SearchStringMultiple(isolate, subject, pattern,
3521 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003522 return *builder.ToJSArray(result_array);
3523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003524 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003525 }
3526
3527 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3528
3529 RegExpImpl::IrregexpResult result;
3530 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003531 result = SearchRegExpNoCaptureMultiple(isolate,
3532 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003533 regexp,
3534 last_match_info,
3535 &builder);
3536 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003537 result = SearchRegExpMultiple(isolate,
3538 subject,
3539 regexp,
3540 last_match_info,
3541 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003542 }
3543 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003545 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3546 return Failure::Exception();
3547}
3548
3549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003550RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003551 NoHandleAllocation ha;
3552 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003553 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003554 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003556 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003557 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003558 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003559 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003560 // Character array used for conversion.
3561 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003562 return isolate->heap()->
3563 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003564 }
3565 }
3566
3567 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003568 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 }
3572 if (isinf(value)) {
3573 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003576 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003579 MaybeObject* result =
3580 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 DeleteArray(str);
3582 return result;
3583}
3584
3585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003586RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003587 NoHandleAllocation ha;
3588 ASSERT(args.length() == 2);
3589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003590 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593 }
3594 if (isinf(value)) {
3595 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003598 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003600 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 int f = FastD2I(f_number);
3602 RUNTIME_ASSERT(f >= 0);
3603 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003604 MaybeObject* res =
3605 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608}
3609
3610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003611RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 NoHandleAllocation ha;
3613 ASSERT(args.length() == 2);
3614
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003615 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 }
3619 if (isinf(value)) {
3620 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003623 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003625 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 int f = FastD2I(f_number);
3627 RUNTIME_ASSERT(f >= -1 && f <= 20);
3628 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 MaybeObject* res =
3630 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633}
3634
3635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003636RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 NoHandleAllocation ha;
3638 ASSERT(args.length() == 2);
3639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003640 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 }
3644 if (isinf(value)) {
3645 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003648 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003650 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 int f = FastD2I(f_number);
3652 RUNTIME_ASSERT(f >= 1 && f <= 21);
3653 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654 MaybeObject* res =
3655 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658}
3659
3660
3661// Returns a single character string where first character equals
3662// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003663static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003664 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003665 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003666 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003667 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003669 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670}
3671
3672
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3674 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003675 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003676 // Handle [] indexing on Strings
3677 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003678 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3679 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003680 }
3681
3682 // Handle [] indexing on String objects
3683 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3685 Handle<Object> result =
3686 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3687 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003691 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003692 return prototype->GetElement(index);
3693 }
3694
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003695 return GetElement(object, index);
3696}
3697
3698
lrn@chromium.org303ada72010-10-27 09:33:13 +00003699MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 return object->GetElement(index);
3701}
3702
3703
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003704MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3705 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003706 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003710 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 isolate->factory()->NewTypeError("non_object_property_load",
3713 HandleVector(args, 2));
3714 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716
3717 // Check if the given key is an array index.
3718 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003719 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 }
3722
3723 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003726 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 bool has_pending_exception = false;
3729 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003730 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003732 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003733 }
3734
ager@chromium.org32912102009-01-16 10:38:43 +00003735 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 // the element if so.
3737 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003738 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003740 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 }
3742}
3743
3744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003745RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 NoHandleAllocation ha;
3747 ASSERT(args.length() == 2);
3748
3749 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003750 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003752 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753}
3754
3755
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003756// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003757RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003758 NoHandleAllocation ha;
3759 ASSERT(args.length() == 2);
3760
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003761 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003762 // itself.
3763 //
3764 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003765 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003766 // global proxy object never has properties. This is the case
3767 // because the global proxy object forwards everything to its hidden
3768 // prototype including local lookups.
3769 //
3770 // Additionally, we need to make sure that we do not cache results
3771 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003772 if (args[0]->IsJSObject() &&
3773 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003774 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003775 args[1]->IsString()) {
3776 JSObject* receiver = JSObject::cast(args[0]);
3777 String* key = String::cast(args[1]);
3778 if (receiver->HasFastProperties()) {
3779 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003781 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3782 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003783 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003784 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003786 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003787 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003788 LookupResult result;
3789 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003790 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003791 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003792 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003793 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003794 }
3795 } else {
3796 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003797 StringDictionary* dictionary = receiver->property_dictionary();
3798 int entry = dictionary->FindEntry(key);
3799 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003800 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003801 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003802 if (!receiver->IsGlobalObject()) return value;
3803 value = JSGlobalPropertyCell::cast(value)->value();
3804 if (!value->IsTheHole()) return value;
3805 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003806 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003807 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003808 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3809 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003810 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003811 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003812 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003813 if (index >= 0 && index < str->length()) {
3814 Handle<Object> result = GetCharAt(str, index);
3815 return *result;
3816 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003817 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003818
3819 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 return Runtime::GetObjectProperty(isolate,
3821 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003822 args.at<Object>(1));
3823}
3824
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003825// Implements part of 8.12.9 DefineOwnProperty.
3826// There are 3 cases that lead here:
3827// Step 4b - define a new accessor property.
3828// Steps 9c & 12 - replace an existing data property with an accessor property.
3829// Step 12 - update an existing accessor property with an accessor or generic
3830// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003831RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003834 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3835 CONVERT_CHECKED(String, name, args[1]);
3836 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003837 Object* fun = args[3];
3838 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003839 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3840 int unchecked = flag_attr->value();
3841 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3842 RUNTIME_ASSERT(!obj->IsNull());
3843 LookupResult result;
3844 obj->LocalLookupRealNamedProperty(name, &result);
3845
3846 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3847 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3848 // delete it to avoid running into trouble in DefineAccessor, which
3849 // handles this incorrectly if the property is readonly (does nothing)
3850 if (result.IsProperty() &&
3851 (result.type() == FIELD || result.type() == NORMAL
3852 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003853 Object* ok;
3854 { MaybeObject* maybe_ok =
3855 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3856 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3857 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003858 }
3859 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3860}
3861
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003862// Implements part of 8.12.9 DefineOwnProperty.
3863// There are 3 cases that lead here:
3864// Step 4a - define a new data property.
3865// Steps 9b & 12 - replace an existing accessor property with a data property.
3866// Step 12 - update an existing data property with a data or generic
3867// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003868RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003869 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003870 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003871 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3872 CONVERT_ARG_CHECKED(String, name, 1);
3873 Handle<Object> obj_value = args.at<Object>(2);
3874
3875 CONVERT_CHECKED(Smi, flag, args[3]);
3876 int unchecked = flag->value();
3877 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3878
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003879 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3880
3881 // Check if this is an element.
3882 uint32_t index;
3883 bool is_element = name->AsArrayIndex(&index);
3884
3885 // Special case for elements if any of the flags are true.
3886 // If elements are in fast case we always implicitly assume that:
3887 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3888 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3889 is_element) {
3890 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003891 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003892 // We do not need to do access checks here since these has already
3893 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003894 Handle<Object> proto(js_object->GetPrototype());
3895 // If proxy is detached, ignore the assignment. Alternatively,
3896 // we could throw an exception.
3897 if (proto->IsNull()) return *obj_value;
3898 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003899 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003900 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003901 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003902 // Make sure that we never go back to fast case.
3903 dictionary->set_requires_slow_elements();
3904 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003905 Handle<NumberDictionary> extended_dictionary =
3906 NumberDictionarySet(dictionary, index, obj_value, details);
3907 if (*extended_dictionary != *dictionary) {
3908 js_object->set_elements(*extended_dictionary);
3909 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003910 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003911 }
3912
ager@chromium.org5c838252010-02-19 08:53:10 +00003913 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003914 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003915
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003916 // To be compatible with safari we do not change the value on API objects
3917 // in defineProperty. Firefox disagrees here, and actually changes the value.
3918 if (result.IsProperty() &&
3919 (result.type() == CALLBACKS) &&
3920 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003921 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003922 }
3923
ager@chromium.org5c838252010-02-19 08:53:10 +00003924 // Take special care when attributes are different and there is already
3925 // a property. For simplicity we normalize the property which enables us
3926 // to not worry about changing the instance_descriptor and creating a new
3927 // map. The current version of SetObjectProperty does not handle attributes
3928 // correctly in the case where a property is a field and is reset with
3929 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003930 if (result.IsProperty() &&
3931 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003932 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003933 if (js_object->IsJSGlobalProxy()) {
3934 // Since the result is a property, the prototype will exist so
3935 // we don't have to check for null.
3936 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003937 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003938 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003939 // Use IgnoreAttributes version since a readonly property may be
3940 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003941 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3942 *obj_value,
3943 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003944 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003946 return Runtime::ForceSetObjectProperty(isolate,
3947 js_object,
3948 name,
3949 obj_value,
3950 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003951}
3952
3953
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003954// Special case for elements if any of the flags are true.
3955// If elements are in fast case we always implicitly assume that:
3956// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3957static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3958 Handle<JSObject> js_object,
3959 uint32_t index,
3960 Handle<Object> value,
3961 PropertyAttributes attr) {
3962 // Normalize the elements to enable attributes on the property.
3963 NormalizeElements(js_object);
3964 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
3965 // Make sure that we never go back to fast case.
3966 dictionary->set_requires_slow_elements();
3967 PropertyDetails details = PropertyDetails(attr, NORMAL);
3968 Handle<NumberDictionary> extended_dictionary =
3969 NumberDictionarySet(dictionary, index, value, details);
3970 if (*extended_dictionary != *dictionary) {
3971 js_object->set_elements(*extended_dictionary);
3972 }
3973 return *value;
3974}
3975
3976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003977MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3978 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003979 Handle<Object> key,
3980 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003981 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003982 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003986 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 isolate->factory()->NewTypeError("non_object_property_store",
3989 HandleVector(args, 2));
3990 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003991 }
3992
3993 // If the object isn't a JavaScript object, we ignore the store.
3994 if (!object->IsJSObject()) return *value;
3995
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003996 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 // 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)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004008 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004012 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4013 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4014 }
4015
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004016 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004017 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 return *value;
4019 }
4020
4021 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004022 Handle<Object> result;
4023 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004024 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4025 return NormalizeObjectSetElement(isolate,
4026 js_object,
4027 index,
4028 value,
4029 attr);
4030 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004031 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004033 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004034 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004035 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004037 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 return *value;
4039 }
4040
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 bool has_pending_exception = false;
4043 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4044 if (has_pending_exception) return Failure::Exception();
4045 Handle<String> name = Handle<String>::cast(converted);
4046
4047 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004048 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004050 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 }
4052}
4053
4054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4056 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004057 Handle<Object> key,
4058 Handle<Object> value,
4059 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004060 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004061
4062 // Check if the given key is an array index.
4063 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004064 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004065 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4066 // of a string using [] notation. We need to support this too in
4067 // JavaScript.
4068 // In the case of a String object we just need to redirect the assignment to
4069 // the underlying string if the index is in range. Since the underlying
4070 // string does nothing with the assignment then we can ignore such
4071 // assignments.
4072 if (js_object->IsStringObjectWithCharacterAt(index)) {
4073 return *value;
4074 }
4075
whesse@chromium.org7b260152011-06-20 15:33:18 +00004076 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004077 }
4078
4079 if (key->IsString()) {
4080 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004081 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004082 } else {
4083 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004084 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004085 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4086 *value,
4087 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004088 }
4089 }
4090
4091 // Call-back into JavaScript to convert the key to a string.
4092 bool has_pending_exception = false;
4093 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4094 if (has_pending_exception) return Failure::Exception();
4095 Handle<String> name = Handle<String>::cast(converted);
4096
4097 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004098 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004099 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004100 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004101 }
4102}
4103
4104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4106 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004107 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004109
4110 // Check if the given key is an array index.
4111 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004112 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004113 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4114 // characters of a string using [] notation. In the case of a
4115 // String object we just need to redirect the deletion to the
4116 // underlying string if the index is in range. Since the
4117 // underlying string does nothing with the deletion, we can ignore
4118 // such deletions.
4119 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004120 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004121 }
4122
4123 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4124 }
4125
4126 Handle<String> key_string;
4127 if (key->IsString()) {
4128 key_string = Handle<String>::cast(key);
4129 } else {
4130 // Call-back into JavaScript to convert the key to a string.
4131 bool has_pending_exception = false;
4132 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4133 if (has_pending_exception) return Failure::Exception();
4134 key_string = Handle<String>::cast(converted);
4135 }
4136
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004137 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004138 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4139}
4140
4141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004142RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004144 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145
4146 Handle<Object> object = args.at<Object>(0);
4147 Handle<Object> key = args.at<Object>(1);
4148 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004149 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004150 RUNTIME_ASSERT(
4151 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004153 PropertyAttributes attributes =
4154 static_cast<PropertyAttributes>(unchecked_attributes);
4155
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004156 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004157 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004158 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004159 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4160 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004161 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004164 return Runtime::SetObjectProperty(isolate,
4165 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004166 key,
4167 value,
4168 attributes,
4169 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170}
4171
4172
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004173// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004174// This is used to decide if we should transform null and undefined
4175// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004176RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004177 NoHandleAllocation ha;
4178 RUNTIME_ASSERT(args.length() == 1);
4179
4180 Handle<Object> object = args.at<Object>(0);
4181
4182 if (object->IsJSFunction()) {
4183 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004184 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004185 }
4186 return isolate->heap()->undefined_value();
4187}
4188
4189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190// Set a local property, even if it is READ_ONLY. If the property does not
4191// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004192RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004194 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 CONVERT_CHECKED(JSObject, object, args[0]);
4196 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004197 // Compute attributes.
4198 PropertyAttributes attributes = NONE;
4199 if (args.length() == 4) {
4200 CONVERT_CHECKED(Smi, value_obj, args[3]);
4201 int unchecked_value = value_obj->value();
4202 // Only attribute bits should be set.
4203 RUNTIME_ASSERT(
4204 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4205 attributes = static_cast<PropertyAttributes>(unchecked_value);
4206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004208 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004209 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210}
4211
4212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004213RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004215 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216
4217 CONVERT_CHECKED(JSObject, object, args[0]);
4218 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004219 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004220 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004221 ? JSObject::STRICT_DELETION
4222 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223}
4224
4225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226static Object* HasLocalPropertyImplementation(Isolate* isolate,
4227 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004228 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004229 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004230 // Handle hidden prototypes. If there's a hidden prototype above this thing
4231 // then we have to check it for properties, because they are supposed to
4232 // look like they are on this object.
4233 Handle<Object> proto(object->GetPrototype());
4234 if (proto->IsJSObject() &&
4235 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 return HasLocalPropertyImplementation(isolate,
4237 Handle<JSObject>::cast(proto),
4238 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004239 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004241}
4242
4243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004244RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004245 NoHandleAllocation ha;
4246 ASSERT(args.length() == 2);
4247 CONVERT_CHECKED(String, key, args[1]);
4248
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004249 uint32_t index;
4250 const bool key_is_array_index = key->AsArrayIndex(&index);
4251
ager@chromium.org9085a012009-05-11 19:22:57 +00004252 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004254 if (obj->IsJSObject()) {
4255 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004256 // Fast case: either the key is a real named property or it is not
4257 // an array index and there are no interceptors or hidden
4258 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004260 Map* map = object->map();
4261 if (!key_is_array_index &&
4262 !map->has_named_interceptor() &&
4263 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4264 return isolate->heap()->false_value();
4265 }
4266 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004267 HandleScope scope(isolate);
4268 return HasLocalPropertyImplementation(isolate,
4269 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004270 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004271 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004273 String* string = String::cast(obj);
4274 if (index < static_cast<uint32_t>(string->length())) {
4275 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004276 }
4277 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004278 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004279}
4280
4281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004282RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004283 NoHandleAllocation na;
4284 ASSERT(args.length() == 2);
4285
4286 // Only JS objects can have properties.
4287 if (args[0]->IsJSObject()) {
4288 JSObject* object = JSObject::cast(args[0]);
4289 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004290 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004293}
4294
4295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004296RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation na;
4298 ASSERT(args.length() == 2);
4299
4300 // Only JS objects can have elements.
4301 if (args[0]->IsJSObject()) {
4302 JSObject* object = JSObject::cast(args[0]);
4303 CONVERT_CHECKED(Smi, index_obj, args[1]);
4304 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308}
4309
4310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004311RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 NoHandleAllocation ha;
4313 ASSERT(args.length() == 2);
4314
4315 CONVERT_CHECKED(JSObject, object, args[0]);
4316 CONVERT_CHECKED(String, key, args[1]);
4317
4318 uint32_t index;
4319 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 }
4322
ager@chromium.org870a0b62008-11-04 11:43:05 +00004323 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004324 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325}
4326
4327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004328RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004330 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004331 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 return *GetKeysFor(object);
4333}
4334
4335
4336// Returns either a FixedArray as Runtime_GetPropertyNames,
4337// or, if the given object has an enum cache that contains
4338// all enumerable properties of the object and its prototypes
4339// have none, the map of the object. This is used to speed up
4340// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004341RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004342 ASSERT(args.length() == 1);
4343
4344 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4345
4346 if (raw_object->IsSimpleEnum()) return raw_object->map();
4347
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004348 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004349 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004350 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4351 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352
4353 // Test again, since cache may have been built by preceding call.
4354 if (object->IsSimpleEnum()) return object->map();
4355
4356 return *content;
4357}
4358
4359
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004360// Find the length of the prototype chain that is to to handled as one. If a
4361// prototype object is hidden it is to be viewed as part of the the object it
4362// is prototype for.
4363static int LocalPrototypeChainLength(JSObject* obj) {
4364 int count = 1;
4365 Object* proto = obj->GetPrototype();
4366 while (proto->IsJSObject() &&
4367 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4368 count++;
4369 proto = JSObject::cast(proto)->GetPrototype();
4370 }
4371 return count;
4372}
4373
4374
4375// Return the names of the local named properties.
4376// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004377RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 ASSERT(args.length() == 1);
4380 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004381 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004382 }
4383 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4384
4385 // Skip the global proxy as it has no properties and always delegates to the
4386 // real global object.
4387 if (obj->IsJSGlobalProxy()) {
4388 // Only collect names if access is permitted.
4389 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004390 !isolate->MayNamedAccess(*obj,
4391 isolate->heap()->undefined_value(),
4392 v8::ACCESS_KEYS)) {
4393 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4394 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004395 }
4396 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4397 }
4398
4399 // Find the number of objects making up this.
4400 int length = LocalPrototypeChainLength(*obj);
4401
4402 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004403 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004404 int total_property_count = 0;
4405 Handle<JSObject> jsproto = obj;
4406 for (int i = 0; i < length; i++) {
4407 // Only collect names if access is permitted.
4408 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 !isolate->MayNamedAccess(*jsproto,
4410 isolate->heap()->undefined_value(),
4411 v8::ACCESS_KEYS)) {
4412 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4413 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004414 }
4415 int n;
4416 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4417 local_property_count[i] = n;
4418 total_property_count += n;
4419 if (i < length - 1) {
4420 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4421 }
4422 }
4423
4424 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 Handle<FixedArray> names =
4426 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004427
4428 // Get the property names.
4429 jsproto = obj;
4430 int proto_with_hidden_properties = 0;
4431 for (int i = 0; i < length; i++) {
4432 jsproto->GetLocalPropertyNames(*names,
4433 i == 0 ? 0 : local_property_count[i - 1]);
4434 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4435 proto_with_hidden_properties++;
4436 }
4437 if (i < length - 1) {
4438 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4439 }
4440 }
4441
4442 // Filter out name of hidden propeties object.
4443 if (proto_with_hidden_properties > 0) {
4444 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004445 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004446 names->length() - proto_with_hidden_properties);
4447 int dest_pos = 0;
4448 for (int i = 0; i < total_property_count; i++) {
4449 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004451 continue;
4452 }
4453 names->set(dest_pos++, name);
4454 }
4455 }
4456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004458}
4459
4460
4461// Return the names of the local indexed properties.
4462// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004463RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004465 ASSERT(args.length() == 1);
4466 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004467 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004468 }
4469 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4470
4471 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004473 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004474 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004475}
4476
4477
4478// Return information on whether an object has a named or indexed interceptor.
4479// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004480RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004481 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004482 ASSERT(args.length() == 1);
4483 if (!args[0]->IsJSObject()) {
4484 return Smi::FromInt(0);
4485 }
4486 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4487
4488 int result = 0;
4489 if (obj->HasNamedInterceptor()) result |= 2;
4490 if (obj->HasIndexedInterceptor()) result |= 1;
4491
4492 return Smi::FromInt(result);
4493}
4494
4495
4496// Return property names from named interceptor.
4497// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004498RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004499 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004500 ASSERT(args.length() == 1);
4501 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4502
4503 if (obj->HasNamedInterceptor()) {
4504 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4505 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4506 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004507 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004508}
4509
4510
4511// Return element names from indexed interceptor.
4512// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004513RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004515 ASSERT(args.length() == 1);
4516 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4517
4518 if (obj->HasIndexedInterceptor()) {
4519 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4520 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4521 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004523}
4524
4525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004526RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004527 ASSERT_EQ(args.length(), 1);
4528 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004529 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004530 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004531
4532 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004533 // Do access checks before going to the global object.
4534 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004535 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004536 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4538 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004539 }
4540
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004541 Handle<Object> proto(object->GetPrototype());
4542 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004543 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004544 object = Handle<JSObject>::cast(proto);
4545 }
4546
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004547 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4548 LOCAL_ONLY);
4549 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4550 // property array and since the result is mutable we have to create
4551 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004552 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004554 for (int i = 0; i < length; i++) {
4555 Object* entry = contents->get(i);
4556 if (entry->IsString()) {
4557 copy->set(i, entry);
4558 } else {
4559 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004560 HandleScope scope(isolate);
4561 Handle<Object> entry_handle(entry, isolate);
4562 Handle<Object> entry_str =
4563 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004564 copy->set(i, *entry_str);
4565 }
4566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004568}
4569
4570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004571RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 NoHandleAllocation ha;
4573 ASSERT(args.length() == 1);
4574
4575 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004576 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 it.AdvanceToArgumentsFrame();
4578 JavaScriptFrame* frame = it.frame();
4579
4580 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004581 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004582
4583 // Try to convert the key to an index. If successful and within
4584 // index return the the argument from the frame.
4585 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004586 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004587 return frame->GetParameter(index);
4588 }
4589
4590 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592 bool exception = false;
4593 Handle<Object> converted =
4594 Execution::ToString(args.at<Object>(0), &exception);
4595 if (exception) return Failure::Exception();
4596 Handle<String> key = Handle<String>::cast(converted);
4597
4598 // Try to convert the string key into an array index.
4599 if (key->AsArrayIndex(&index)) {
4600 if (index < n) {
4601 return frame->GetParameter(index);
4602 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 }
4605 }
4606
4607 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004608 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4609 if (key->Equals(isolate->heap()->callee_symbol())) {
4610 Object* function = frame->function();
4611 if (function->IsJSFunction() &&
4612 JSFunction::cast(function)->shared()->strict_mode()) {
4613 return isolate->Throw(*isolate->factory()->NewTypeError(
4614 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4615 }
4616 return function;
4617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618
4619 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621}
4622
4623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004624RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004625 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004626
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004627 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004628 Handle<Object> object = args.at<Object>(0);
4629 if (object->IsJSObject()) {
4630 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004631 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004632 MaybeObject* ok = js_object->TransformToFastProperties(0);
4633 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004634 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004635 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004636 return *object;
4637}
4638
4639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004640RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004641 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004642
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004643 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004644 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004645 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004646 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004647 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004648 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004649 return *object;
4650}
4651
4652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004653RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004654 NoHandleAllocation ha;
4655 ASSERT(args.length() == 1);
4656
4657 return args[0]->ToBoolean();
4658}
4659
4660
4661// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4662// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004663RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664 NoHandleAllocation ha;
4665
4666 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 HeapObject* heap_obj = HeapObject::cast(obj);
4669
4670 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004671 if (heap_obj->map()->is_undetectable()) {
4672 return isolate->heap()->undefined_symbol();
4673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674
4675 InstanceType instance_type = heap_obj->map()->instance_type();
4676 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 }
4679
4680 switch (instance_type) {
4681 case ODDBALL_TYPE:
4682 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684 }
4685 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004686 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687 }
4688 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004689 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004690 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004691 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 default:
4693 // For any kind of object not handled above, the spec rule for
4694 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004695 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 }
4697}
4698
4699
lrn@chromium.org25156de2010-04-06 13:10:27 +00004700static bool AreDigits(const char*s, int from, int to) {
4701 for (int i = from; i < to; i++) {
4702 if (s[i] < '0' || s[i] > '9') return false;
4703 }
4704
4705 return true;
4706}
4707
4708
4709static int ParseDecimalInteger(const char*s, int from, int to) {
4710 ASSERT(to - from < 10); // Overflow is not possible.
4711 ASSERT(from < to);
4712 int d = s[from] - '0';
4713
4714 for (int i = from + 1; i < to; i++) {
4715 d = 10 * d + (s[i] - '0');
4716 }
4717
4718 return d;
4719}
4720
4721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004722RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723 NoHandleAllocation ha;
4724 ASSERT(args.length() == 1);
4725 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004726 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004727
4728 // Fast case: short integer or some sorts of junk values.
4729 int len = subject->length();
4730 if (subject->IsSeqAsciiString()) {
4731 if (len == 0) return Smi::FromInt(0);
4732
4733 char const* data = SeqAsciiString::cast(subject)->GetChars();
4734 bool minus = (data[0] == '-');
4735 int start_pos = (minus ? 1 : 0);
4736
4737 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004738 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004739 } else if (data[start_pos] > '9') {
4740 // Fast check for a junk value. A valid string may start from a
4741 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4742 // the 'I' character ('Infinity'). All of that have codes not greater than
4743 // '9' except 'I'.
4744 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004746 }
4747 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4748 // The maximal/minimal smi has 10 digits. If the string has less digits we
4749 // know it will fit into the smi-data type.
4750 int d = ParseDecimalInteger(data, start_pos, len);
4751 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004753 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004754 } else if (!subject->HasHashCode() &&
4755 len <= String::kMaxArrayIndexSize &&
4756 (len == 1 || data[0] != '0')) {
4757 // String hash is not calculated yet but all the data are present.
4758 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004759 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004760#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004761 subject->Hash(); // Force hash calculation.
4762 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4763 static_cast<int>(hash));
4764#endif
4765 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004766 }
4767 return Smi::FromInt(d);
4768 }
4769 }
4770
4771 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004772 return isolate->heap()->NumberFromDouble(
4773 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774}
4775
4776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004777RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 NoHandleAllocation ha;
4779 ASSERT(args.length() == 1);
4780
4781 CONVERT_CHECKED(JSArray, codes, args[0]);
4782 int length = Smi::cast(codes->length())->value();
4783
4784 // Check if the string can be ASCII.
4785 int i;
4786 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004787 Object* element;
4788 { MaybeObject* maybe_element = codes->GetElement(i);
4789 // We probably can't get an exception here, but just in order to enforce
4790 // the checking of inputs in the runtime calls we check here.
4791 if (!maybe_element->ToObject(&element)) return maybe_element;
4792 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4794 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4795 break;
4796 }
4797
lrn@chromium.org303ada72010-10-27 09:33:13 +00004798 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004800 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004802 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803 }
4804
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805 Object* object = NULL;
4806 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 String* result = String::cast(object);
4808 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004809 Object* element;
4810 { MaybeObject* maybe_element = codes->GetElement(i);
4811 if (!maybe_element->ToObject(&element)) return maybe_element;
4812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004814 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815 }
4816 return result;
4817}
4818
4819
4820// kNotEscaped is generated by the following:
4821//
4822// #!/bin/perl
4823// for (my $i = 0; $i < 256; $i++) {
4824// print "\n" if $i % 16 == 0;
4825// my $c = chr($i);
4826// my $escaped = 1;
4827// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4828// print $escaped ? "0, " : "1, ";
4829// }
4830
4831
4832static bool IsNotEscaped(uint16_t character) {
4833 // Only for 8 bit characters, the rest are always escaped (in a different way)
4834 ASSERT(character < 256);
4835 static const char kNotEscaped[256] = {
4836 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4837 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4838 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4839 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
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, 0, 0, 0, 0, 1,
4842 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4843 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4844 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4845 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4846 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4847 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4848 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4849 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4850 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4851 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4852 };
4853 return kNotEscaped[character] != 0;
4854}
4855
4856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004857RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 const char hex_chars[] = "0123456789ABCDEF";
4859 NoHandleAllocation ha;
4860 ASSERT(args.length() == 1);
4861 CONVERT_CHECKED(String, source, args[0]);
4862
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004863 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864
4865 int escaped_length = 0;
4866 int length = source->length();
4867 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 Access<StringInputBuffer> buffer(
4869 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 buffer->Reset(source);
4871 while (buffer->has_more()) {
4872 uint16_t character = buffer->GetNext();
4873 if (character >= 256) {
4874 escaped_length += 6;
4875 } else if (IsNotEscaped(character)) {
4876 escaped_length++;
4877 } else {
4878 escaped_length += 3;
4879 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004880 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004881 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004882 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004883 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884 return Failure::OutOfMemoryException();
4885 }
4886 }
4887 }
4888 // No length change implies no change. Return original string if no change.
4889 if (escaped_length == length) {
4890 return source;
4891 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004892 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004893 { MaybeObject* maybe_o =
4894 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004895 if (!maybe_o->ToObject(&o)) return maybe_o;
4896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897 String* destination = String::cast(o);
4898 int dest_position = 0;
4899
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004900 Access<StringInputBuffer> buffer(
4901 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 buffer->Rewind();
4903 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004904 uint16_t chr = buffer->GetNext();
4905 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004906 destination->Set(dest_position, '%');
4907 destination->Set(dest_position+1, 'u');
4908 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4909 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4910 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4911 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004912 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004913 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004914 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 dest_position++;
4916 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004917 destination->Set(dest_position, '%');
4918 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4919 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920 dest_position += 3;
4921 }
4922 }
4923 return destination;
4924}
4925
4926
4927static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4928 static const signed char kHexValue['g'] = {
4929 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4930 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4931 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4932 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4933 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4934 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4935 -1, 10, 11, 12, 13, 14, 15 };
4936
4937 if (character1 > 'f') return -1;
4938 int hi = kHexValue[character1];
4939 if (hi == -1) return -1;
4940 if (character2 > 'f') return -1;
4941 int lo = kHexValue[character2];
4942 if (lo == -1) return -1;
4943 return (hi << 4) + lo;
4944}
4945
4946
ager@chromium.org870a0b62008-11-04 11:43:05 +00004947static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004948 int i,
4949 int length,
4950 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004951 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004952 int32_t hi = 0;
4953 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004954 if (character == '%' &&
4955 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004956 source->Get(i + 1) == 'u' &&
4957 (hi = TwoDigitHex(source->Get(i + 2),
4958 source->Get(i + 3))) != -1 &&
4959 (lo = TwoDigitHex(source->Get(i + 4),
4960 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004961 *step = 6;
4962 return (hi << 8) + lo;
4963 } else if (character == '%' &&
4964 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004965 (lo = TwoDigitHex(source->Get(i + 1),
4966 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004967 *step = 3;
4968 return lo;
4969 } else {
4970 *step = 1;
4971 return character;
4972 }
4973}
4974
4975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004976RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004977 NoHandleAllocation ha;
4978 ASSERT(args.length() == 1);
4979 CONVERT_CHECKED(String, source, args[0]);
4980
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004981 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982
4983 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004984 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985
4986 int unescaped_length = 0;
4987 for (int i = 0; i < length; unescaped_length++) {
4988 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004992 i += step;
4993 }
4994
4995 // No length change implies no change. Return original string if no change.
4996 if (unescaped_length == length)
4997 return source;
4998
lrn@chromium.org303ada72010-10-27 09:33:13 +00004999 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000 { MaybeObject* maybe_o =
5001 ascii ?
5002 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5003 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005004 if (!maybe_o->ToObject(&o)) return maybe_o;
5005 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006 String* destination = String::cast(o);
5007
5008 int dest_position = 0;
5009 for (int i = 0; i < length; dest_position++) {
5010 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005011 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005012 i += step;
5013 }
5014 return destination;
5015}
5016
5017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005018static const unsigned int kQuoteTableLength = 128u;
5019
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005020static const int kJsonQuotesCharactersPerEntry = 8;
5021static const char* const JsonQuotes =
5022 "\\u0000 \\u0001 \\u0002 \\u0003 "
5023 "\\u0004 \\u0005 \\u0006 \\u0007 "
5024 "\\b \\t \\n \\u000b "
5025 "\\f \\r \\u000e \\u000f "
5026 "\\u0010 \\u0011 \\u0012 \\u0013 "
5027 "\\u0014 \\u0015 \\u0016 \\u0017 "
5028 "\\u0018 \\u0019 \\u001a \\u001b "
5029 "\\u001c \\u001d \\u001e \\u001f "
5030 " ! \\\" # "
5031 "$ % & ' "
5032 "( ) * + "
5033 ", - . / "
5034 "0 1 2 3 "
5035 "4 5 6 7 "
5036 "8 9 : ; "
5037 "< = > ? "
5038 "@ A B C "
5039 "D E F G "
5040 "H I J K "
5041 "L M N O "
5042 "P Q R S "
5043 "T U V W "
5044 "X Y Z [ "
5045 "\\\\ ] ^ _ "
5046 "` a b c "
5047 "d e f g "
5048 "h i j k "
5049 "l m n o "
5050 "p q r s "
5051 "t u v w "
5052 "x y z { "
5053 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005054
5055
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005056// For a string that is less than 32k characters it should always be
5057// possible to allocate it in new space.
5058static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5059
5060
5061// Doing JSON quoting cannot make the string more than this many times larger.
5062static const int kJsonQuoteWorstCaseBlowup = 6;
5063
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005064static const int kSpaceForQuotesAndComma = 3;
5065static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005066
5067// Covers the entire ASCII range (all other characters are unchanged by JSON
5068// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069static const byte JsonQuoteLengths[kQuoteTableLength] = {
5070 6, 6, 6, 6, 6, 6, 6, 6,
5071 2, 2, 2, 6, 2, 2, 6, 6,
5072 6, 6, 6, 6, 6, 6, 6, 6,
5073 6, 6, 6, 6, 6, 6, 6, 6,
5074 1, 1, 2, 1, 1, 1, 1, 1,
5075 1, 1, 1, 1, 1, 1, 1, 1,
5076 1, 1, 1, 1, 1, 1, 1, 1,
5077 1, 1, 1, 1, 1, 1, 1, 1,
5078 1, 1, 1, 1, 1, 1, 1, 1,
5079 1, 1, 1, 1, 1, 1, 1, 1,
5080 1, 1, 1, 1, 1, 1, 1, 1,
5081 1, 1, 1, 1, 2, 1, 1, 1,
5082 1, 1, 1, 1, 1, 1, 1, 1,
5083 1, 1, 1, 1, 1, 1, 1, 1,
5084 1, 1, 1, 1, 1, 1, 1, 1,
5085 1, 1, 1, 1, 1, 1, 1, 1,
5086};
5087
5088
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005089template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005090MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005091
5092
5093template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5095 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005096}
5097
5098
5099template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5101 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005102}
5103
5104
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005105template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5107 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005108 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005109 const Char* read_cursor = characters.start();
5110 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005111 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005112 int quoted_length = kSpaceForQuotes;
5113 while (read_cursor < end) {
5114 Char c = *(read_cursor++);
5115 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5116 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005117 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005118 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005119 }
5120 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005121 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5122 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005123 Object* new_object;
5124 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005125 return new_alloc;
5126 }
5127 StringType* new_string = StringType::cast(new_object);
5128
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005129 Char* write_cursor = reinterpret_cast<Char*>(
5130 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005131 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005132 *(write_cursor++) = '"';
5133
5134 read_cursor = characters.start();
5135 while (read_cursor < end) {
5136 Char c = *(read_cursor++);
5137 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5138 *(write_cursor++) = c;
5139 } else {
5140 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5141 const char* replacement = JsonQuotes +
5142 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5143 for (int i = 0; i < len; i++) {
5144 *write_cursor++ = *replacement++;
5145 }
5146 }
5147 }
5148 *(write_cursor++) = '"';
5149 return new_string;
5150}
5151
5152
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005153template <typename SinkChar, typename SourceChar>
5154static inline SinkChar* WriteQuoteJsonString(
5155 Isolate* isolate,
5156 SinkChar* write_cursor,
5157 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005158 // SinkChar is only char if SourceChar is guaranteed to be char.
5159 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005160 const SourceChar* read_cursor = characters.start();
5161 const SourceChar* end = read_cursor + characters.length();
5162 *(write_cursor++) = '"';
5163 while (read_cursor < end) {
5164 SourceChar c = *(read_cursor++);
5165 if (sizeof(SourceChar) > 1u &&
5166 static_cast<unsigned>(c) >= kQuoteTableLength) {
5167 *(write_cursor++) = static_cast<SinkChar>(c);
5168 } else {
5169 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5170 const char* replacement = JsonQuotes +
5171 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5172 write_cursor[0] = replacement[0];
5173 if (len > 1) {
5174 write_cursor[1] = replacement[1];
5175 if (len > 2) {
5176 ASSERT(len == 6);
5177 write_cursor[2] = replacement[2];
5178 write_cursor[3] = replacement[3];
5179 write_cursor[4] = replacement[4];
5180 write_cursor[5] = replacement[5];
5181 }
5182 }
5183 write_cursor += len;
5184 }
5185 }
5186 *(write_cursor++) = '"';
5187 return write_cursor;
5188}
5189
5190
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005191template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192static MaybeObject* QuoteJsonString(Isolate* isolate,
5193 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005194 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005196 int worst_case_length =
5197 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005198 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005200 }
5201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005202 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5203 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005204 Object* new_object;
5205 if (!new_alloc->ToObject(&new_object)) {
5206 return new_alloc;
5207 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005209 // Even if our string is small enough to fit in new space we still have to
5210 // handle it being allocated in old space as may happen in the third
5211 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5212 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005214 }
5215 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005217
5218 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5219 Char* write_cursor = reinterpret_cast<Char*>(
5220 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005221 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005222 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5223 write_cursor,
5224 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005225 int final_length = static_cast<int>(
5226 write_cursor - reinterpret_cast<Char*>(
5227 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005228 isolate->heap()->new_space()->
5229 template ShrinkStringAtAllocationBoundary<StringType>(
5230 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005231 return new_string;
5232}
5233
5234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005235RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005236 NoHandleAllocation ha;
5237 CONVERT_CHECKED(String, str, args[0]);
5238 if (!str->IsFlat()) {
5239 MaybeObject* try_flatten = str->TryFlatten();
5240 Object* flat;
5241 if (!try_flatten->ToObject(&flat)) {
5242 return try_flatten;
5243 }
5244 str = String::cast(flat);
5245 ASSERT(str->IsFlat());
5246 }
5247 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005248 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5249 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005250 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005251 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5252 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005253 }
5254}
5255
5256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005257RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005258 NoHandleAllocation ha;
5259 CONVERT_CHECKED(String, str, args[0]);
5260 if (!str->IsFlat()) {
5261 MaybeObject* try_flatten = str->TryFlatten();
5262 Object* flat;
5263 if (!try_flatten->ToObject(&flat)) {
5264 return try_flatten;
5265 }
5266 str = String::cast(flat);
5267 ASSERT(str->IsFlat());
5268 }
5269 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005270 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5271 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005272 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005273 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5274 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005275 }
5276}
5277
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005278
5279template <typename Char, typename StringType>
5280static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5281 FixedArray* array,
5282 int worst_case_length) {
5283 int length = array->length();
5284
5285 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5286 worst_case_length);
5287 Object* new_object;
5288 if (!new_alloc->ToObject(&new_object)) {
5289 return new_alloc;
5290 }
5291 if (!isolate->heap()->new_space()->Contains(new_object)) {
5292 // Even if our string is small enough to fit in new space we still have to
5293 // handle it being allocated in old space as may happen in the third
5294 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5295 // CEntryStub::GenerateCore.
5296 return isolate->heap()->undefined_value();
5297 }
5298 AssertNoAllocation no_gc;
5299 StringType* new_string = StringType::cast(new_object);
5300 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5301
5302 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5303 Char* write_cursor = reinterpret_cast<Char*>(
5304 new_string->address() + SeqAsciiString::kHeaderSize);
5305 *(write_cursor++) = '[';
5306 for (int i = 0; i < length; i++) {
5307 if (i != 0) *(write_cursor++) = ',';
5308 String* str = String::cast(array->get(i));
5309 if (str->IsTwoByteRepresentation()) {
5310 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5311 write_cursor,
5312 str->ToUC16Vector());
5313 } else {
5314 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5315 write_cursor,
5316 str->ToAsciiVector());
5317 }
5318 }
5319 *(write_cursor++) = ']';
5320
5321 int final_length = static_cast<int>(
5322 write_cursor - reinterpret_cast<Char*>(
5323 new_string->address() + SeqAsciiString::kHeaderSize));
5324 isolate->heap()->new_space()->
5325 template ShrinkStringAtAllocationBoundary<StringType>(
5326 new_string, final_length);
5327 return new_string;
5328}
5329
5330
5331RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5332 NoHandleAllocation ha;
5333 ASSERT(args.length() == 1);
5334 CONVERT_CHECKED(JSArray, array, args[0]);
5335
5336 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5337 FixedArray* elements = FixedArray::cast(array->elements());
5338 int n = elements->length();
5339 bool ascii = true;
5340 int total_length = 0;
5341
5342 for (int i = 0; i < n; i++) {
5343 Object* elt = elements->get(i);
5344 if (!elt->IsString()) return isolate->heap()->undefined_value();
5345 String* element = String::cast(elt);
5346 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5347 total_length += element->length();
5348 if (ascii && element->IsTwoByteRepresentation()) {
5349 ascii = false;
5350 }
5351 }
5352
5353 int worst_case_length =
5354 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5355 + total_length * kJsonQuoteWorstCaseBlowup;
5356
5357 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5358 return isolate->heap()->undefined_value();
5359 }
5360
5361 if (ascii) {
5362 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5363 elements,
5364 worst_case_length);
5365 } else {
5366 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5367 elements,
5368 worst_case_length);
5369 }
5370}
5371
5372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005373RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 NoHandleAllocation ha;
5375
5376 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005377 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005379 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380
lrn@chromium.org25156de2010-04-06 13:10:27 +00005381 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005382 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005383 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384}
5385
5386
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005387RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 NoHandleAllocation ha;
5389 CONVERT_CHECKED(String, str, args[0]);
5390
5391 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005392 double value = StringToDouble(isolate->unicode_cache(),
5393 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005394
5395 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005396 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397}
5398
5399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005400template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005401MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005402 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005403 String* s,
5404 int length,
5405 int input_string_length,
5406 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005407 // We try this twice, once with the assumption that the result is no longer
5408 // than the input and, if that assumption breaks, again with the exact
5409 // length. This may not be pretty, but it is nicer than what was here before
5410 // and I hereby claim my vaffel-is.
5411 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 // Allocate the resulting string.
5413 //
5414 // NOTE: This assumes that the upper/lower case of an ascii
5415 // character is also ascii. This is currently the case, but it
5416 // might break in the future if we implement more context and locale
5417 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005418 Object* o;
5419 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 ? isolate->heap()->AllocateRawAsciiString(length)
5421 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005422 if (!maybe_o->ToObject(&o)) return maybe_o;
5423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 String* result = String::cast(o);
5425 bool has_changed_character = false;
5426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 // Convert all characters to upper case, assuming that they will fit
5428 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005429 Access<StringInputBuffer> buffer(
5430 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005432 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 // We can assume that the string is not empty
5434 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005435 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005436 bool has_next = buffer->has_more();
5437 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005438 int char_length = mapping->get(current, next, chars);
5439 if (char_length == 0) {
5440 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005442 i++;
5443 } else if (char_length == 1) {
5444 // Common case: converting the letter resulted in one character.
5445 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005446 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 has_changed_character = true;
5448 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005449 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005450 // We've assumed that the result would be as long as the
5451 // input but here is a character that converts to several
5452 // characters. No matter, we calculate the exact length
5453 // of the result and try the whole thing again.
5454 //
5455 // Note that this leaves room for optimization. We could just
5456 // memcpy what we already have to the result string. Also,
5457 // the result string is the last object allocated we could
5458 // "realloc" it and probably, in the vast majority of cases,
5459 // extend the existing string to be able to hold the full
5460 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005461 int next_length = 0;
5462 if (has_next) {
5463 next_length = mapping->get(next, 0, chars);
5464 if (next_length == 0) next_length = 1;
5465 }
5466 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467 while (buffer->has_more()) {
5468 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005469 // NOTE: we use 0 as the next character here because, while
5470 // the next character may affect what a character converts to,
5471 // it does not in any case affect the length of what it convert
5472 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 int char_length = mapping->get(current, 0, chars);
5474 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005475 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005477 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478 return Failure::OutOfMemoryException();
5479 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005481 // Try again with the real length.
5482 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483 } else {
5484 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005485 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486 i++;
5487 }
5488 has_changed_character = true;
5489 }
5490 current = next;
5491 }
5492 if (has_changed_character) {
5493 return result;
5494 } else {
5495 // If we didn't actually change anything in doing the conversion
5496 // we simple return the result and let the converted string
5497 // become garbage; there is no reason to keep two identical strings
5498 // alive.
5499 return s;
5500 }
5501}
5502
5503
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005504namespace {
5505
lrn@chromium.org303ada72010-10-27 09:33:13 +00005506static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5507
5508
5509// Given a word and two range boundaries returns a word with high bit
5510// set in every byte iff the corresponding input byte was strictly in
5511// the range (m, n). All the other bits in the result are cleared.
5512// This function is only useful when it can be inlined and the
5513// boundaries are statically known.
5514// Requires: all bytes in the input word and the boundaries must be
5515// ascii (less than 0x7F).
5516static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5517 // Every byte in an ascii string is less than or equal to 0x7F.
5518 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5519 // Use strict inequalities since in edge cases the function could be
5520 // further simplified.
5521 ASSERT(0 < m && m < n && n < 0x7F);
5522 // Has high bit set in every w byte less than n.
5523 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5524 // Has high bit set in every w byte greater than m.
5525 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5526 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5527}
5528
5529
5530enum AsciiCaseConversion {
5531 ASCII_TO_LOWER,
5532 ASCII_TO_UPPER
5533};
5534
5535
5536template <AsciiCaseConversion dir>
5537struct FastAsciiConverter {
5538 static bool Convert(char* dst, char* src, int length) {
5539#ifdef DEBUG
5540 char* saved_dst = dst;
5541 char* saved_src = src;
5542#endif
5543 // We rely on the distance between upper and lower case letters
5544 // being a known power of 2.
5545 ASSERT('a' - 'A' == (1 << 5));
5546 // Boundaries for the range of input characters than require conversion.
5547 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5548 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5549 bool changed = false;
5550 char* const limit = src + length;
5551#ifdef V8_HOST_CAN_READ_UNALIGNED
5552 // Process the prefix of the input that requires no conversion one
5553 // (machine) word at a time.
5554 while (src <= limit - sizeof(uintptr_t)) {
5555 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5556 if (AsciiRangeMask(w, lo, hi) != 0) {
5557 changed = true;
5558 break;
5559 }
5560 *reinterpret_cast<uintptr_t*>(dst) = w;
5561 src += sizeof(uintptr_t);
5562 dst += sizeof(uintptr_t);
5563 }
5564 // Process the remainder of the input performing conversion when
5565 // required one word at a time.
5566 while (src <= limit - sizeof(uintptr_t)) {
5567 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5568 uintptr_t m = AsciiRangeMask(w, lo, hi);
5569 // The mask has high (7th) bit set in every byte that needs
5570 // conversion and we know that the distance between cases is
5571 // 1 << 5.
5572 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5573 src += sizeof(uintptr_t);
5574 dst += sizeof(uintptr_t);
5575 }
5576#endif
5577 // Process the last few bytes of the input (or the whole input if
5578 // unaligned access is not supported).
5579 while (src < limit) {
5580 char c = *src;
5581 if (lo < c && c < hi) {
5582 c ^= (1 << 5);
5583 changed = true;
5584 }
5585 *dst = c;
5586 ++src;
5587 ++dst;
5588 }
5589#ifdef DEBUG
5590 CheckConvert(saved_dst, saved_src, length, changed);
5591#endif
5592 return changed;
5593 }
5594
5595#ifdef DEBUG
5596 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5597 bool expected_changed = false;
5598 for (int i = 0; i < length; i++) {
5599 if (dst[i] == src[i]) continue;
5600 expected_changed = true;
5601 if (dir == ASCII_TO_LOWER) {
5602 ASSERT('A' <= src[i] && src[i] <= 'Z');
5603 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5604 } else {
5605 ASSERT(dir == ASCII_TO_UPPER);
5606 ASSERT('a' <= src[i] && src[i] <= 'z');
5607 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5608 }
5609 }
5610 ASSERT(expected_changed == changed);
5611 }
5612#endif
5613};
5614
5615
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005616struct ToLowerTraits {
5617 typedef unibrow::ToLowercase UnibrowConverter;
5618
lrn@chromium.org303ada72010-10-27 09:33:13 +00005619 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005620};
5621
5622
5623struct ToUpperTraits {
5624 typedef unibrow::ToUppercase UnibrowConverter;
5625
lrn@chromium.org303ada72010-10-27 09:33:13 +00005626 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005627};
5628
5629} // namespace
5630
5631
5632template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005633MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005634 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005636 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005637 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005638 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005639 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005640
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005641 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005642 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643 if (length == 0) return s;
5644
5645 // Simpler handling of ascii strings.
5646 //
5647 // NOTE: This assumes that the upper/lower case of an ascii
5648 // character is also ascii. This is currently the case, but it
5649 // might break in the future if we implement more context and locale
5650 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005651 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005652 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005653 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005654 if (!maybe_o->ToObject(&o)) return maybe_o;
5655 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005656 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005657 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005658 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 return has_changed_character ? result : s;
5660 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661
lrn@chromium.org303ada72010-10-27 09:33:13 +00005662 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005663 { MaybeObject* maybe_answer =
5664 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005665 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5666 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005667 if (answer->IsSmi()) {
5668 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005669 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005670 ConvertCaseHelper(isolate,
5671 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005672 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5673 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005674 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005675 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005676}
5677
5678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005679RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005680 return ConvertCase<ToLowerTraits>(
5681 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682}
5683
5684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005685RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686 return ConvertCase<ToUpperTraits>(
5687 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005688}
5689
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005690
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005691static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5692 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5693}
5694
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005696RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005697 NoHandleAllocation ha;
5698 ASSERT(args.length() == 3);
5699
5700 CONVERT_CHECKED(String, s, args[0]);
5701 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5702 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5703
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005704 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005705 int length = s->length();
5706
5707 int left = 0;
5708 if (trimLeft) {
5709 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5710 left++;
5711 }
5712 }
5713
5714 int right = length;
5715 if (trimRight) {
5716 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5717 right--;
5718 }
5719 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005720 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005721}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005722
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005723
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005724template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005725void FindStringIndices(Isolate* isolate,
5726 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005727 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005728 ZoneList<int>* indices,
5729 unsigned int limit) {
5730 ASSERT(limit > 0);
5731 // Collect indices of pattern in subject, and the end-of-string index.
5732 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005734 int pattern_length = pattern.length();
5735 int index = 0;
5736 while (limit > 0) {
5737 index = search.Search(subject, index);
5738 if (index < 0) return;
5739 indices->Add(index);
5740 index += pattern_length;
5741 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005742 }
5743}
5744
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005746RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005747 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005749 CONVERT_ARG_CHECKED(String, subject, 0);
5750 CONVERT_ARG_CHECKED(String, pattern, 1);
5751 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5752
5753 int subject_length = subject->length();
5754 int pattern_length = pattern->length();
5755 RUNTIME_ASSERT(pattern_length > 0);
5756
5757 // The limit can be very large (0xffffffffu), but since the pattern
5758 // isn't empty, we can never create more parts than ~half the length
5759 // of the subject.
5760
5761 if (!subject->IsFlat()) FlattenString(subject);
5762
5763 static const int kMaxInitialListCapacity = 16;
5764
danno@chromium.org40cb8782011-05-25 07:58:50 +00005765 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005766
5767 // Find (up to limit) indices of separator and end-of-string in subject
5768 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5769 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005770 if (!pattern->IsFlat()) FlattenString(pattern);
5771
5772 // No allocation block.
5773 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005774 AssertNoAllocation nogc;
5775 if (subject->IsAsciiRepresentation()) {
5776 Vector<const char> subject_vector = subject->ToAsciiVector();
5777 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005778 FindStringIndices(isolate,
5779 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005780 pattern->ToAsciiVector(),
5781 &indices,
5782 limit);
5783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 FindStringIndices(isolate,
5785 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005786 pattern->ToUC16Vector(),
5787 &indices,
5788 limit);
5789 }
5790 } else {
5791 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5792 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 FindStringIndices(isolate,
5794 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005795 pattern->ToAsciiVector(),
5796 &indices,
5797 limit);
5798 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005799 FindStringIndices(isolate,
5800 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005801 pattern->ToUC16Vector(),
5802 &indices,
5803 limit);
5804 }
5805 }
5806 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005807
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005808 if (static_cast<uint32_t>(indices.length()) < limit) {
5809 indices.Add(subject_length);
5810 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005811
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005812 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005813
5814 // Create JSArray of substrings separated by separator.
5815 int part_count = indices.length();
5816
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005817 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005818 result->set_length(Smi::FromInt(part_count));
5819
5820 ASSERT(result->HasFastElements());
5821
5822 if (part_count == 1 && indices.at(0) == subject_length) {
5823 FixedArray::cast(result->elements())->set(0, *subject);
5824 return *result;
5825 }
5826
5827 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5828 int part_start = 0;
5829 for (int i = 0; i < part_count; i++) {
5830 HandleScope local_loop_handle;
5831 int part_end = indices.at(i);
5832 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005833 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005834 elements->set(i, *substring);
5835 part_start = part_end + pattern_length;
5836 }
5837
5838 return *result;
5839}
5840
5841
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005842// Copies ascii characters to the given fixed array looking up
5843// one-char strings in the cache. Gives up on the first char that is
5844// not in the cache and fills the remainder with smi zeros. Returns
5845// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005846static int CopyCachedAsciiCharsToArray(Heap* heap,
5847 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005848 FixedArray* elements,
5849 int length) {
5850 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005851 FixedArray* ascii_cache = heap->single_character_string_cache();
5852 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005853 int i;
5854 for (i = 0; i < length; ++i) {
5855 Object* value = ascii_cache->get(chars[i]);
5856 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005857 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005858 elements->set(i, value, SKIP_WRITE_BARRIER);
5859 }
5860 if (i < length) {
5861 ASSERT(Smi::FromInt(0) == 0);
5862 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5863 }
5864#ifdef DEBUG
5865 for (int j = 0; j < length; ++j) {
5866 Object* element = elements->get(j);
5867 ASSERT(element == Smi::FromInt(0) ||
5868 (element->IsString() && String::cast(element)->LooksValid()));
5869 }
5870#endif
5871 return i;
5872}
5873
5874
5875// Converts a String to JSArray.
5876// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005878 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005879 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005880 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005881 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882
5883 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005884 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005885
5886 Handle<FixedArray> elements;
5887 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005888 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005889 { MaybeObject* maybe_obj =
5890 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005891 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5892 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005893 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894
5895 Vector<const char> chars = s->ToAsciiVector();
5896 // Note, this will initialize all elements (not only the prefix)
5897 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5899 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005900 *elements,
5901 length);
5902
5903 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005904 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5905 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005906 }
5907 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005908 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005909 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005910 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5911 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005912 }
5913 }
5914
5915#ifdef DEBUG
5916 for (int i = 0; i < length; ++i) {
5917 ASSERT(String::cast(elements->get(i))->length() == 1);
5918 }
5919#endif
5920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005921 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005922}
5923
5924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005925RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005926 NoHandleAllocation ha;
5927 ASSERT(args.length() == 1);
5928 CONVERT_CHECKED(String, value, args[0]);
5929 return value->ToObject();
5930}
5931
5932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005933bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005934 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005935 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005936 return char_length == 0;
5937}
5938
5939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005940RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 NoHandleAllocation ha;
5942 ASSERT(args.length() == 1);
5943
5944 Object* number = args[0];
5945 RUNTIME_ASSERT(number->IsNumber());
5946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005947 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948}
5949
5950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005951RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005952 NoHandleAllocation ha;
5953 ASSERT(args.length() == 1);
5954
5955 Object* number = args[0];
5956 RUNTIME_ASSERT(number->IsNumber());
5957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005958 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005959}
5960
5961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005962RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963 NoHandleAllocation ha;
5964 ASSERT(args.length() == 1);
5965
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005966 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005967
5968 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5969 if (number > 0 && number <= Smi::kMaxValue) {
5970 return Smi::FromInt(static_cast<int>(number));
5971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005972 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973}
5974
5975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005976RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005977 NoHandleAllocation ha;
5978 ASSERT(args.length() == 1);
5979
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005980 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005981
5982 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5983 if (number > 0 && number <= Smi::kMaxValue) {
5984 return Smi::FromInt(static_cast<int>(number));
5985 }
5986
5987 double double_value = DoubleToInteger(number);
5988 // Map both -0 and +0 to +0.
5989 if (double_value == 0) double_value = 0;
5990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005991 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005992}
5993
5994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005995RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996 NoHandleAllocation ha;
5997 ASSERT(args.length() == 1);
5998
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005999 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001}
6002
6003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006004RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005 NoHandleAllocation ha;
6006 ASSERT(args.length() == 1);
6007
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006008 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006009
6010 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6011 if (number > 0 && number <= Smi::kMaxValue) {
6012 return Smi::FromInt(static_cast<int>(number));
6013 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006014 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015}
6016
6017
ager@chromium.org870a0b62008-11-04 11:43:05 +00006018// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6019// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006020RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006021 NoHandleAllocation ha;
6022 ASSERT(args.length() == 1);
6023
6024 Object* obj = args[0];
6025 if (obj->IsSmi()) {
6026 return obj;
6027 }
6028 if (obj->IsHeapNumber()) {
6029 double value = HeapNumber::cast(obj)->value();
6030 int int_value = FastD2I(value);
6031 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6032 return Smi::FromInt(int_value);
6033 }
6034 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006035 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006036}
6037
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006039RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006040 NoHandleAllocation ha;
6041 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006042 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006043}
6044
6045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006046RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047 NoHandleAllocation ha;
6048 ASSERT(args.length() == 2);
6049
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006050 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6051 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053}
6054
6055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006056RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057 NoHandleAllocation ha;
6058 ASSERT(args.length() == 2);
6059
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006060 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6061 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006062 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063}
6064
6065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006066RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067 NoHandleAllocation ha;
6068 ASSERT(args.length() == 2);
6069
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006070 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6071 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006072 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006073}
6074
6075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006076RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077 NoHandleAllocation ha;
6078 ASSERT(args.length() == 1);
6079
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006080 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006081 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082}
6083
6084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006085RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006086 NoHandleAllocation ha;
6087 ASSERT(args.length() == 0);
6088
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006089 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006090}
6091
6092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006093RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006094 NoHandleAllocation ha;
6095 ASSERT(args.length() == 2);
6096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006097 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6098 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006100}
6101
6102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006103RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006104 NoHandleAllocation ha;
6105 ASSERT(args.length() == 2);
6106
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006107 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6108 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006109
ager@chromium.org3811b432009-10-28 14:53:37 +00006110 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006111 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006112 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113}
6114
6115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006116RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117 NoHandleAllocation ha;
6118 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006119 CONVERT_CHECKED(String, str1, args[0]);
6120 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006121 isolate->counters()->string_add_runtime()->Increment();
6122 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006123}
6124
6125
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006126template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006127static inline void StringBuilderConcatHelper(String* special,
6128 sinkchar* sink,
6129 FixedArray* fixed_array,
6130 int array_length) {
6131 int position = 0;
6132 for (int i = 0; i < array_length; i++) {
6133 Object* element = fixed_array->get(i);
6134 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006135 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006136 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006137 int pos;
6138 int len;
6139 if (encoded_slice > 0) {
6140 // Position and length encoded in one smi.
6141 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6142 len = StringBuilderSubstringLength::decode(encoded_slice);
6143 } else {
6144 // Position and length encoded in two smis.
6145 Object* obj = fixed_array->get(++i);
6146 ASSERT(obj->IsSmi());
6147 pos = Smi::cast(obj)->value();
6148 len = -encoded_slice;
6149 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006150 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006151 sink + position,
6152 pos,
6153 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006154 position += len;
6155 } else {
6156 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006157 int element_length = string->length();
6158 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006159 position += element_length;
6160 }
6161 }
6162}
6163
6164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006165RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006166 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006167 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006169 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006170 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006171 return Failure::OutOfMemoryException();
6172 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006173 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006174 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006175
6176 // This assumption is used by the slice encoding in one or two smis.
6177 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6178
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006179 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006180 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006181 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006182 }
6183 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006184 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187
6188 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190 } else if (array_length == 1) {
6191 Object* first = fixed_array->get(0);
6192 if (first->IsString()) return first;
6193 }
6194
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006195 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196 int position = 0;
6197 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006198 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006199 Object* elt = fixed_array->get(i);
6200 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006201 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006202 int smi_value = Smi::cast(elt)->value();
6203 int pos;
6204 int len;
6205 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006206 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006207 pos = StringBuilderSubstringPosition::decode(smi_value);
6208 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006209 } else {
6210 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006211 len = -smi_value;
6212 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006213 i++;
6214 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006216 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006217 Object* next_smi = fixed_array->get(i);
6218 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006219 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006220 }
6221 pos = Smi::cast(next_smi)->value();
6222 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006223 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006225 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006226 ASSERT(pos >= 0);
6227 ASSERT(len >= 0);
6228 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006230 }
6231 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232 } else if (elt->IsString()) {
6233 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006234 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006235 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006236 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006237 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006240 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006242 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006244 return Failure::OutOfMemoryException();
6245 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006246 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247 }
6248
6249 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006251
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006253 { MaybeObject* maybe_object =
6254 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255 if (!maybe_object->ToObject(&object)) return maybe_object;
6256 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006257 SeqAsciiString* answer = SeqAsciiString::cast(object);
6258 StringBuilderConcatHelper(special,
6259 answer->GetChars(),
6260 fixed_array,
6261 array_length);
6262 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006263 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006264 { MaybeObject* maybe_object =
6265 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006266 if (!maybe_object->ToObject(&object)) return maybe_object;
6267 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006268 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6269 StringBuilderConcatHelper(special,
6270 answer->GetChars(),
6271 fixed_array,
6272 array_length);
6273 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006275}
6276
6277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006278RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006279 NoHandleAllocation ha;
6280 ASSERT(args.length() == 3);
6281 CONVERT_CHECKED(JSArray, array, args[0]);
6282 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006283 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006284 return Failure::OutOfMemoryException();
6285 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006286 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006287 CONVERT_CHECKED(String, separator, args[2]);
6288
6289 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006290 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006291 }
6292 FixedArray* fixed_array = FixedArray::cast(array->elements());
6293 if (fixed_array->length() < array_length) {
6294 array_length = fixed_array->length();
6295 }
6296
6297 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006298 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006299 } else if (array_length == 1) {
6300 Object* first = fixed_array->get(0);
6301 if (first->IsString()) return first;
6302 }
6303
6304 int separator_length = separator->length();
6305 int max_nof_separators =
6306 (String::kMaxLength + separator_length - 1) / separator_length;
6307 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006308 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006309 return Failure::OutOfMemoryException();
6310 }
6311 int length = (array_length - 1) * separator_length;
6312 for (int i = 0; i < array_length; i++) {
6313 Object* element_obj = fixed_array->get(i);
6314 if (!element_obj->IsString()) {
6315 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006316 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006317 }
6318 String* element = String::cast(element_obj);
6319 int increment = element->length();
6320 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006321 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006322 return Failure::OutOfMemoryException();
6323 }
6324 length += increment;
6325 }
6326
6327 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006328 { MaybeObject* maybe_object =
6329 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006330 if (!maybe_object->ToObject(&object)) return maybe_object;
6331 }
6332 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6333
6334 uc16* sink = answer->GetChars();
6335#ifdef DEBUG
6336 uc16* end = sink + length;
6337#endif
6338
6339 String* first = String::cast(fixed_array->get(0));
6340 int first_length = first->length();
6341 String::WriteToFlat(first, sink, 0, first_length);
6342 sink += first_length;
6343
6344 for (int i = 1; i < array_length; i++) {
6345 ASSERT(sink + separator_length <= end);
6346 String::WriteToFlat(separator, sink, 0, separator_length);
6347 sink += separator_length;
6348
6349 String* element = String::cast(fixed_array->get(i));
6350 int element_length = element->length();
6351 ASSERT(sink + element_length <= end);
6352 String::WriteToFlat(element, sink, 0, element_length);
6353 sink += element_length;
6354 }
6355 ASSERT(sink == end);
6356
6357 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6358 return answer;
6359}
6360
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006361template <typename Char>
6362static void JoinSparseArrayWithSeparator(FixedArray* elements,
6363 int elements_length,
6364 uint32_t array_length,
6365 String* separator,
6366 Vector<Char> buffer) {
6367 int previous_separator_position = 0;
6368 int separator_length = separator->length();
6369 int cursor = 0;
6370 for (int i = 0; i < elements_length; i += 2) {
6371 int position = NumberToInt32(elements->get(i));
6372 String* string = String::cast(elements->get(i + 1));
6373 int string_length = string->length();
6374 if (string->length() > 0) {
6375 while (previous_separator_position < position) {
6376 String::WriteToFlat<Char>(separator, &buffer[cursor],
6377 0, separator_length);
6378 cursor += separator_length;
6379 previous_separator_position++;
6380 }
6381 String::WriteToFlat<Char>(string, &buffer[cursor],
6382 0, string_length);
6383 cursor += string->length();
6384 }
6385 }
6386 if (separator_length > 0) {
6387 // Array length must be representable as a signed 32-bit number,
6388 // otherwise the total string length would have been too large.
6389 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6390 int last_array_index = static_cast<int>(array_length - 1);
6391 while (previous_separator_position < last_array_index) {
6392 String::WriteToFlat<Char>(separator, &buffer[cursor],
6393 0, separator_length);
6394 cursor += separator_length;
6395 previous_separator_position++;
6396 }
6397 }
6398 ASSERT(cursor <= buffer.length());
6399}
6400
6401
6402RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6403 NoHandleAllocation ha;
6404 ASSERT(args.length() == 3);
6405 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6406 RUNTIME_ASSERT(elements_array->HasFastElements());
6407 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6408 CONVERT_CHECKED(String, separator, args[2]);
6409 // elements_array is fast-mode JSarray of alternating positions
6410 // (increasing order) and strings.
6411 // array_length is length of original array (used to add separators);
6412 // separator is string to put between elements. Assumed to be non-empty.
6413
6414 // Find total length of join result.
6415 int string_length = 0;
6416 bool is_ascii = true;
6417 int max_string_length = SeqAsciiString::kMaxLength;
6418 bool overflow = false;
6419 CONVERT_NUMBER_CHECKED(int, elements_length,
6420 Int32, elements_array->length());
6421 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6422 FixedArray* elements = FixedArray::cast(elements_array->elements());
6423 for (int i = 0; i < elements_length; i += 2) {
6424 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6425 CONVERT_CHECKED(String, string, elements->get(i + 1));
6426 int length = string->length();
6427 if (is_ascii && !string->IsAsciiRepresentation()) {
6428 is_ascii = false;
6429 max_string_length = SeqTwoByteString::kMaxLength;
6430 }
6431 if (length > max_string_length ||
6432 max_string_length - length < string_length) {
6433 overflow = true;
6434 break;
6435 }
6436 string_length += length;
6437 }
6438 int separator_length = separator->length();
6439 if (!overflow && separator_length > 0) {
6440 if (array_length <= 0x7fffffffu) {
6441 int separator_count = static_cast<int>(array_length) - 1;
6442 int remaining_length = max_string_length - string_length;
6443 if ((remaining_length / separator_length) >= separator_count) {
6444 string_length += separator_length * (array_length - 1);
6445 } else {
6446 // Not room for the separators within the maximal string length.
6447 overflow = true;
6448 }
6449 } else {
6450 // Nonempty separator and at least 2^31-1 separators necessary
6451 // means that the string is too large to create.
6452 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6453 overflow = true;
6454 }
6455 }
6456 if (overflow) {
6457 // Throw OutOfMemory exception for creating too large a string.
6458 V8::FatalProcessOutOfMemory("Array join result too large.");
6459 }
6460
6461 if (is_ascii) {
6462 MaybeObject* result_allocation =
6463 isolate->heap()->AllocateRawAsciiString(string_length);
6464 if (result_allocation->IsFailure()) return result_allocation;
6465 SeqAsciiString* result_string =
6466 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6467 JoinSparseArrayWithSeparator<char>(elements,
6468 elements_length,
6469 array_length,
6470 separator,
6471 Vector<char>(result_string->GetChars(),
6472 string_length));
6473 return result_string;
6474 } else {
6475 MaybeObject* result_allocation =
6476 isolate->heap()->AllocateRawTwoByteString(string_length);
6477 if (result_allocation->IsFailure()) return result_allocation;
6478 SeqTwoByteString* result_string =
6479 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6480 JoinSparseArrayWithSeparator<uc16>(elements,
6481 elements_length,
6482 array_length,
6483 separator,
6484 Vector<uc16>(result_string->GetChars(),
6485 string_length));
6486 return result_string;
6487 }
6488}
6489
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006491RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 2);
6494
6495 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6496 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006497 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006498}
6499
6500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006501RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502 NoHandleAllocation ha;
6503 ASSERT(args.length() == 2);
6504
6505 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6506 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508}
6509
6510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006511RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512 NoHandleAllocation ha;
6513 ASSERT(args.length() == 2);
6514
6515 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6516 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006517 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006518}
6519
6520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006522 NoHandleAllocation ha;
6523 ASSERT(args.length() == 1);
6524
6525 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527}
6528
6529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006530RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531 NoHandleAllocation ha;
6532 ASSERT(args.length() == 2);
6533
6534 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6535 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006536 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537}
6538
6539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006540RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541 NoHandleAllocation ha;
6542 ASSERT(args.length() == 2);
6543
6544 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6545 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006546 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547}
6548
6549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006550RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551 NoHandleAllocation ha;
6552 ASSERT(args.length() == 2);
6553
6554 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6555 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006556 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557}
6558
6559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006560RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561 NoHandleAllocation ha;
6562 ASSERT(args.length() == 2);
6563
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006564 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6565 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6567 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6568 if (x == y) return Smi::FromInt(EQUAL);
6569 Object* result;
6570 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6571 result = Smi::FromInt(EQUAL);
6572 } else {
6573 result = Smi::FromInt(NOT_EQUAL);
6574 }
6575 return result;
6576}
6577
6578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006579RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580 NoHandleAllocation ha;
6581 ASSERT(args.length() == 2);
6582
6583 CONVERT_CHECKED(String, x, args[0]);
6584 CONVERT_CHECKED(String, y, args[1]);
6585
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006586 bool not_equal = !x->Equals(y);
6587 // This is slightly convoluted because the value that signifies
6588 // equality is 0 and inequality is 1 so we have to negate the result
6589 // from String::Equals.
6590 ASSERT(not_equal == 0 || not_equal == 1);
6591 STATIC_CHECK(EQUAL == 0);
6592 STATIC_CHECK(NOT_EQUAL == 1);
6593 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594}
6595
6596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598 NoHandleAllocation ha;
6599 ASSERT(args.length() == 3);
6600
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006601 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6602 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 if (isnan(x) || isnan(y)) return args[2];
6604 if (x == y) return Smi::FromInt(EQUAL);
6605 if (isless(x, y)) return Smi::FromInt(LESS);
6606 return Smi::FromInt(GREATER);
6607}
6608
6609
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006610// Compare two Smis as if they were converted to strings and then
6611// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006612RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006613 NoHandleAllocation ha;
6614 ASSERT(args.length() == 2);
6615
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006616 // Extract the integer values from the Smis.
6617 CONVERT_CHECKED(Smi, x, args[0]);
6618 CONVERT_CHECKED(Smi, y, args[1]);
6619 int x_value = x->value();
6620 int y_value = y->value();
6621
6622 // If the integers are equal so are the string representations.
6623 if (x_value == y_value) return Smi::FromInt(EQUAL);
6624
6625 // If one of the integers are zero the normal integer order is the
6626 // same as the lexicographic order of the string representations.
6627 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6628
ager@chromium.org32912102009-01-16 10:38:43 +00006629 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006630 // smallest because the char code of '-' is less than the char code
6631 // of any digit. Otherwise, we make both values positive.
6632 if (x_value < 0 || y_value < 0) {
6633 if (y_value >= 0) return Smi::FromInt(LESS);
6634 if (x_value >= 0) return Smi::FromInt(GREATER);
6635 x_value = -x_value;
6636 y_value = -y_value;
6637 }
6638
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006639 // Arrays for the individual characters of the two Smis. Smis are
6640 // 31 bit integers and 10 decimal digits are therefore enough.
6641 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6642 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6643 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6644
6645
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006646 // Convert the integers to arrays of their decimal digits.
6647 int x_index = 0;
6648 int y_index = 0;
6649 while (x_value > 0) {
6650 x_elms[x_index++] = x_value % 10;
6651 x_value /= 10;
6652 }
6653 while (y_value > 0) {
6654 y_elms[y_index++] = y_value % 10;
6655 y_value /= 10;
6656 }
6657
6658 // Loop through the arrays of decimal digits finding the first place
6659 // where they differ.
6660 while (--x_index >= 0 && --y_index >= 0) {
6661 int diff = x_elms[x_index] - y_elms[y_index];
6662 if (diff != 0) return Smi::FromInt(diff);
6663 }
6664
6665 // If one array is a suffix of the other array, the longest array is
6666 // the representation of the largest of the Smis in the
6667 // lexicographic ordering.
6668 return Smi::FromInt(x_index - y_index);
6669}
6670
6671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006672static Object* StringInputBufferCompare(RuntimeState* state,
6673 String* x,
6674 String* y) {
6675 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6676 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006677 bufx.Reset(x);
6678 bufy.Reset(y);
6679 while (bufx.has_more() && bufy.has_more()) {
6680 int d = bufx.GetNext() - bufy.GetNext();
6681 if (d < 0) return Smi::FromInt(LESS);
6682 else if (d > 0) return Smi::FromInt(GREATER);
6683 }
6684
6685 // x is (non-trivial) prefix of y:
6686 if (bufy.has_more()) return Smi::FromInt(LESS);
6687 // y is prefix of x:
6688 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6689}
6690
6691
6692static Object* FlatStringCompare(String* x, String* y) {
6693 ASSERT(x->IsFlat());
6694 ASSERT(y->IsFlat());
6695 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6696 int prefix_length = x->length();
6697 if (y->length() < prefix_length) {
6698 prefix_length = y->length();
6699 equal_prefix_result = Smi::FromInt(GREATER);
6700 } else if (y->length() > prefix_length) {
6701 equal_prefix_result = Smi::FromInt(LESS);
6702 }
6703 int r;
6704 if (x->IsAsciiRepresentation()) {
6705 Vector<const char> x_chars = x->ToAsciiVector();
6706 if (y->IsAsciiRepresentation()) {
6707 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006708 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006709 } else {
6710 Vector<const uc16> y_chars = y->ToUC16Vector();
6711 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6712 }
6713 } else {
6714 Vector<const uc16> x_chars = x->ToUC16Vector();
6715 if (y->IsAsciiRepresentation()) {
6716 Vector<const char> y_chars = y->ToAsciiVector();
6717 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6718 } else {
6719 Vector<const uc16> y_chars = y->ToUC16Vector();
6720 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6721 }
6722 }
6723 Object* result;
6724 if (r == 0) {
6725 result = equal_prefix_result;
6726 } else {
6727 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6728 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006729 ASSERT(result ==
6730 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006731 return result;
6732}
6733
6734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006735RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736 NoHandleAllocation ha;
6737 ASSERT(args.length() == 2);
6738
6739 CONVERT_CHECKED(String, x, args[0]);
6740 CONVERT_CHECKED(String, y, args[1]);
6741
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006743
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 // A few fast case tests before we flatten.
6745 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006746 if (y->length() == 0) {
6747 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006749 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 return Smi::FromInt(LESS);
6751 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006752
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006753 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006754 if (d < 0) return Smi::FromInt(LESS);
6755 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756
lrn@chromium.org303ada72010-10-27 09:33:13 +00006757 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006758 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006759 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6760 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006762 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6763 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006765 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006766 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767}
6768
6769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006770RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006771 NoHandleAllocation ha;
6772 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006775 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006776 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777}
6778
6779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006780RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006781 NoHandleAllocation ha;
6782 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006783 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006785 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787}
6788
6789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006790RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006791 NoHandleAllocation ha;
6792 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006795 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797}
6798
6799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006800static const double kPiDividedBy4 = 0.78539816339744830962;
6801
6802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006803RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 NoHandleAllocation ha;
6805 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006808 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6809 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 double result;
6811 if (isinf(x) && isinf(y)) {
6812 // Make sure that the result in case of two infinite arguments
6813 // is a multiple of Pi / 4. The sign of the result is determined
6814 // by the first argument (x) and the sign of the second argument
6815 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 int multiplier = (x < 0) ? -1 : 1;
6817 if (y < 0) multiplier *= 3;
6818 result = multiplier * kPiDividedBy4;
6819 } else {
6820 result = atan2(x, y);
6821 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006822 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823}
6824
6825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006826RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006827 NoHandleAllocation ha;
6828 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006829 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006831 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833}
6834
6835
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006836RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 NoHandleAllocation ha;
6838 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006839 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006841 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006842 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006843}
6844
6845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006846RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847 NoHandleAllocation ha;
6848 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006849 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006851 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006852 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853}
6854
6855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006856RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857 NoHandleAllocation ha;
6858 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006859 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006861 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006862 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863}
6864
6865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006866RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867 NoHandleAllocation ha;
6868 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006869 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006871 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006873}
6874
6875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006876RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877 NoHandleAllocation ha;
6878 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006881 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006882
6883 // If the second argument is a smi, it is much faster to call the
6884 // custom powi() function than the generic pow().
6885 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006886 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006887 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006888 }
6889
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006890 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006892}
6893
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006894// Fast version of Math.pow if we know that y is not an integer and
6895// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006896RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006897 NoHandleAllocation ha;
6898 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006899 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6900 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006901 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006902 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006903 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006904 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006905 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006906 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006907 }
6908}
6909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006911RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006912 NoHandleAllocation ha;
6913 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006916 if (!args[0]->IsHeapNumber()) {
6917 // Must be smi. Return the argument unchanged for all the other types
6918 // to make fuzz-natives test happy.
6919 return args[0];
6920 }
6921
6922 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6923
6924 double value = number->value();
6925 int exponent = number->get_exponent();
6926 int sign = number->get_sign();
6927
danno@chromium.org160a7b02011-04-18 15:51:38 +00006928 if (exponent < -1) {
6929 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6930 if (sign) return isolate->heap()->minus_zero_value();
6931 return Smi::FromInt(0);
6932 }
6933
6934 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6935 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6936 // agument holds for 32-bit smis).
6937 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006938 return Smi::FromInt(static_cast<int>(value + 0.5));
6939 }
6940
6941 // If the magnitude is big enough, there's no place for fraction part. If we
6942 // try to add 0.5 to this number, 1.0 will be added instead.
6943 if (exponent >= 52) {
6944 return number;
6945 }
6946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006947 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006948
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006949 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006950 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006951}
6952
6953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006954RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006955 NoHandleAllocation ha;
6956 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006957 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006959 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961}
6962
6963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006964RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006965 NoHandleAllocation ha;
6966 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006967 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006969 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006970 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006971}
6972
6973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006974RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975 NoHandleAllocation ha;
6976 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006977 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006978
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006979 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006980 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981}
6982
6983
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006984static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006985 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6986 181, 212, 243, 273, 304, 334};
6987 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6988 182, 213, 244, 274, 305, 335};
6989
6990 year += month / 12;
6991 month %= 12;
6992 if (month < 0) {
6993 year--;
6994 month += 12;
6995 }
6996
6997 ASSERT(month >= 0);
6998 ASSERT(month < 12);
6999
7000 // year_delta is an arbitrary number such that:
7001 // a) year_delta = -1 (mod 400)
7002 // b) year + year_delta > 0 for years in the range defined by
7003 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7004 // Jan 1 1970. This is required so that we don't run into integer
7005 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007006 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007007 // operations.
7008 static const int year_delta = 399999;
7009 static const int base_day = 365 * (1970 + year_delta) +
7010 (1970 + year_delta) / 4 -
7011 (1970 + year_delta) / 100 +
7012 (1970 + year_delta) / 400;
7013
7014 int year1 = year + year_delta;
7015 int day_from_year = 365 * year1 +
7016 year1 / 4 -
7017 year1 / 100 +
7018 year1 / 400 -
7019 base_day;
7020
7021 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007022 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007023 }
7024
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007025 return day_from_year + day_from_month_leap[month] + day - 1;
7026}
7027
7028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007029RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007030 NoHandleAllocation ha;
7031 ASSERT(args.length() == 3);
7032
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007033 CONVERT_SMI_ARG_CHECKED(year, 0);
7034 CONVERT_SMI_ARG_CHECKED(month, 1);
7035 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007036
7037 return Smi::FromInt(MakeDay(year, month, date));
7038}
7039
7040
7041static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7042static const int kDaysIn4Years = 4 * 365 + 1;
7043static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7044static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7045static const int kDays1970to2000 = 30 * 365 + 7;
7046static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7047 kDays1970to2000;
7048static const int kYearsOffset = 400000;
7049
7050static const char kDayInYear[] = {
7051 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7052 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7053 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7054 22, 23, 24, 25, 26, 27, 28,
7055 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7056 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7057 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7058 22, 23, 24, 25, 26, 27, 28, 29, 30,
7059 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7060 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7061 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7062 22, 23, 24, 25, 26, 27, 28, 29, 30,
7063 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7064 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7065 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7066 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7068 22, 23, 24, 25, 26, 27, 28, 29, 30,
7069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7070 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7071 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7072 22, 23, 24, 25, 26, 27, 28, 29, 30,
7073 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7074 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7075
7076 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7077 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7078 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7079 22, 23, 24, 25, 26, 27, 28,
7080 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7081 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7082 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7083 22, 23, 24, 25, 26, 27, 28, 29, 30,
7084 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7085 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7087 22, 23, 24, 25, 26, 27, 28, 29, 30,
7088 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7089 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7090 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7091 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7093 22, 23, 24, 25, 26, 27, 28, 29, 30,
7094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7095 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7097 22, 23, 24, 25, 26, 27, 28, 29, 30,
7098 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7099 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7100
7101 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7102 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7103 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7104 22, 23, 24, 25, 26, 27, 28, 29,
7105 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7106 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7107 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7108 22, 23, 24, 25, 26, 27, 28, 29, 30,
7109 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7110 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7111 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7112 22, 23, 24, 25, 26, 27, 28, 29, 30,
7113 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7114 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7115 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7116 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7117 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7118 22, 23, 24, 25, 26, 27, 28, 29, 30,
7119 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7120 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7121 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7122 22, 23, 24, 25, 26, 27, 28, 29, 30,
7123 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7124 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7125
7126 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7127 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7128 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7129 22, 23, 24, 25, 26, 27, 28,
7130 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7131 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7132 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7133 22, 23, 24, 25, 26, 27, 28, 29, 30,
7134 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7135 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7136 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7137 22, 23, 24, 25, 26, 27, 28, 29, 30,
7138 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7139 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7140 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7141 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7142 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7143 22, 23, 24, 25, 26, 27, 28, 29, 30,
7144 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7145 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7146 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7147 22, 23, 24, 25, 26, 27, 28, 29, 30,
7148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7149 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7150
7151static const char kMonthInYear[] = {
7152 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,
7153 0, 0, 0, 0, 0, 0,
7154 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,
7155 1, 1, 1,
7156 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,
7157 2, 2, 2, 2, 2, 2,
7158 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,
7159 3, 3, 3, 3, 3,
7160 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,
7161 4, 4, 4, 4, 4, 4,
7162 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,
7163 5, 5, 5, 5, 5,
7164 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,
7165 6, 6, 6, 6, 6, 6,
7166 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,
7167 7, 7, 7, 7, 7, 7,
7168 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,
7169 8, 8, 8, 8, 8,
7170 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,
7171 9, 9, 9, 9, 9, 9,
7172 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7173 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7174 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7175 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7176
7177 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,
7178 0, 0, 0, 0, 0, 0,
7179 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,
7180 1, 1, 1,
7181 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,
7182 2, 2, 2, 2, 2, 2,
7183 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,
7184 3, 3, 3, 3, 3,
7185 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,
7186 4, 4, 4, 4, 4, 4,
7187 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,
7188 5, 5, 5, 5, 5,
7189 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,
7190 6, 6, 6, 6, 6, 6,
7191 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,
7192 7, 7, 7, 7, 7, 7,
7193 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,
7194 8, 8, 8, 8, 8,
7195 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,
7196 9, 9, 9, 9, 9, 9,
7197 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7198 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7199 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7200 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7201
7202 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,
7203 0, 0, 0, 0, 0, 0,
7204 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,
7205 1, 1, 1, 1,
7206 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,
7207 2, 2, 2, 2, 2, 2,
7208 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,
7209 3, 3, 3, 3, 3,
7210 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,
7211 4, 4, 4, 4, 4, 4,
7212 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,
7213 5, 5, 5, 5, 5,
7214 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,
7215 6, 6, 6, 6, 6, 6,
7216 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,
7217 7, 7, 7, 7, 7, 7,
7218 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,
7219 8, 8, 8, 8, 8,
7220 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,
7221 9, 9, 9, 9, 9, 9,
7222 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7223 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7224 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7225 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7226
7227 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,
7228 0, 0, 0, 0, 0, 0,
7229 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,
7230 1, 1, 1,
7231 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,
7232 2, 2, 2, 2, 2, 2,
7233 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,
7234 3, 3, 3, 3, 3,
7235 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,
7236 4, 4, 4, 4, 4, 4,
7237 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,
7238 5, 5, 5, 5, 5,
7239 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,
7240 6, 6, 6, 6, 6, 6,
7241 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,
7242 7, 7, 7, 7, 7, 7,
7243 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,
7244 8, 8, 8, 8, 8,
7245 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,
7246 9, 9, 9, 9, 9, 9,
7247 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7248 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7249 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7250 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7251
7252
7253// This function works for dates from 1970 to 2099.
7254static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007255 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007256#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007257 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007258#endif
7259
7260 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7261 date %= kDaysIn4Years;
7262
7263 month = kMonthInYear[date];
7264 day = kDayInYear[date];
7265
7266 ASSERT(MakeDay(year, month, day) == save_date);
7267}
7268
7269
7270static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007271 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007272#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007273 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007274#endif
7275
7276 date += kDaysOffset;
7277 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7278 date %= kDaysIn400Years;
7279
7280 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7281
7282 date--;
7283 int yd1 = date / kDaysIn100Years;
7284 date %= kDaysIn100Years;
7285 year += 100 * yd1;
7286
7287 date++;
7288 int yd2 = date / kDaysIn4Years;
7289 date %= kDaysIn4Years;
7290 year += 4 * yd2;
7291
7292 date--;
7293 int yd3 = date / 365;
7294 date %= 365;
7295 year += yd3;
7296
7297 bool is_leap = (!yd1 || yd2) && !yd3;
7298
7299 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007300 ASSERT(is_leap || (date >= 0));
7301 ASSERT((date < 365) || (is_leap && (date < 366)));
7302 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7303 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7304 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007305
7306 if (is_leap) {
7307 day = kDayInYear[2*365 + 1 + date];
7308 month = kMonthInYear[2*365 + 1 + date];
7309 } else {
7310 day = kDayInYear[date];
7311 month = kMonthInYear[date];
7312 }
7313
7314 ASSERT(MakeDay(year, month, day) == save_date);
7315}
7316
7317
7318static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007319 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007320 if (date >= 0 && date < 32 * kDaysIn4Years) {
7321 DateYMDFromTimeAfter1970(date, year, month, day);
7322 } else {
7323 DateYMDFromTimeSlow(date, year, month, day);
7324 }
7325}
7326
7327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007328RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007329 NoHandleAllocation ha;
7330 ASSERT(args.length() == 2);
7331
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007332 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007333 CONVERT_CHECKED(JSArray, res_array, args[1]);
7334
7335 int year, month, day;
7336 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7337
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 RUNTIME_ASSERT(res_array->elements()->map() ==
7339 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007340 FixedArray* elms = FixedArray::cast(res_array->elements());
7341 RUNTIME_ASSERT(elms->length() == 3);
7342
7343 elms->set(0, Smi::FromInt(year));
7344 elms->set(1, Smi::FromInt(month));
7345 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007346
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007348}
7349
7350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007351RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007352 HandleScope scope(isolate);
7353 ASSERT(args.length() == 3);
7354
7355 Handle<JSFunction> callee = args.at<JSFunction>(0);
7356 Object** parameters = reinterpret_cast<Object**>(args[1]);
7357 const int argument_count = Smi::cast(args[2])->value();
7358
7359 Handle<JSObject> result =
7360 isolate->factory()->NewArgumentsObject(callee, argument_count);
7361 // Allocate the elements if needed.
7362 int parameter_count = callee->shared()->formal_parameter_count();
7363 if (argument_count > 0) {
7364 if (parameter_count > 0) {
7365 int mapped_count = Min(argument_count, parameter_count);
7366 Handle<FixedArray> parameter_map =
7367 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7368 parameter_map->set_map(
7369 isolate->heap()->non_strict_arguments_elements_map());
7370
7371 Handle<Map> old_map(result->map());
7372 Handle<Map> new_map =
7373 isolate->factory()->CopyMapDropTransitions(old_map);
7374 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7375
7376 result->set_map(*new_map);
7377 result->set_elements(*parameter_map);
7378
7379 // Store the context and the arguments array at the beginning of the
7380 // parameter map.
7381 Handle<Context> context(isolate->context());
7382 Handle<FixedArray> arguments =
7383 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7384 parameter_map->set(0, *context);
7385 parameter_map->set(1, *arguments);
7386
7387 // Loop over the actual parameters backwards.
7388 int index = argument_count - 1;
7389 while (index >= mapped_count) {
7390 // These go directly in the arguments array and have no
7391 // corresponding slot in the parameter map.
7392 arguments->set(index, *(parameters - index - 1));
7393 --index;
7394 }
7395
7396 ScopeInfo<> scope_info(callee->shared()->scope_info());
7397 while (index >= 0) {
7398 // Detect duplicate names to the right in the parameter list.
7399 Handle<String> name = scope_info.parameter_name(index);
7400 int context_slot_count = scope_info.number_of_context_slots();
7401 bool duplicate = false;
7402 for (int j = index + 1; j < parameter_count; ++j) {
7403 if (scope_info.parameter_name(j).is_identical_to(name)) {
7404 duplicate = true;
7405 break;
7406 }
7407 }
7408
7409 if (duplicate) {
7410 // This goes directly in the arguments array with a hole in the
7411 // parameter map.
7412 arguments->set(index, *(parameters - index - 1));
7413 parameter_map->set_the_hole(index + 2);
7414 } else {
7415 // The context index goes in the parameter map with a hole in the
7416 // arguments array.
7417 int context_index = -1;
7418 for (int j = Context::MIN_CONTEXT_SLOTS;
7419 j < context_slot_count;
7420 ++j) {
7421 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7422 context_index = j;
7423 break;
7424 }
7425 }
7426 ASSERT(context_index >= 0);
7427 arguments->set_the_hole(index);
7428 parameter_map->set(index + 2, Smi::FromInt(context_index));
7429 }
7430
7431 --index;
7432 }
7433 } else {
7434 // If there is no aliasing, the arguments object elements are not
7435 // special in any way.
7436 Handle<FixedArray> elements =
7437 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7438 result->set_elements(*elements);
7439 for (int i = 0; i < argument_count; ++i) {
7440 elements->set(i, *(parameters - i - 1));
7441 }
7442 }
7443 }
7444 return *result;
7445}
7446
7447
7448RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007449 NoHandleAllocation ha;
7450 ASSERT(args.length() == 3);
7451
7452 JSFunction* callee = JSFunction::cast(args[0]);
7453 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007454 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007455
lrn@chromium.org303ada72010-10-27 09:33:13 +00007456 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007457 { MaybeObject* maybe_result =
7458 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007459 if (!maybe_result->ToObject(&result)) return maybe_result;
7460 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007461 // Allocate the elements if needed.
7462 if (length > 0) {
7463 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007464 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007465 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007466 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7467 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007468
7469 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007470 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007471 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007472 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007473
7474 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007475 for (int i = 0; i < length; i++) {
7476 array->set(i, *--parameters, mode);
7477 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007478 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007479 }
7480 return result;
7481}
7482
7483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007484RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007485 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007486 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007487 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007488 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007489 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490
whesse@chromium.org7b260152011-06-20 15:33:18 +00007491 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007492 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007493 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007495 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7496 context,
7497 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498 return *result;
7499}
7500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007501
7502static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7503 int* total_argc) {
7504 // Find frame containing arguments passed to the caller.
7505 JavaScriptFrameIterator it;
7506 JavaScriptFrame* frame = it.frame();
7507 List<JSFunction*> functions(2);
7508 frame->GetFunctions(&functions);
7509 if (functions.length() > 1) {
7510 int inlined_frame_index = functions.length() - 1;
7511 JSFunction* inlined_function = functions[inlined_frame_index];
7512 int args_count = inlined_function->shared()->formal_parameter_count();
7513 ScopedVector<SlotRef> args_slots(args_count);
7514 SlotRef::ComputeSlotMappingForArguments(frame,
7515 inlined_frame_index,
7516 &args_slots);
7517
7518 *total_argc = bound_argc + args_count;
7519 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7520 for (int i = 0; i < args_count; i++) {
7521 Handle<Object> val = args_slots[i].GetValue();
7522 param_data[bound_argc + i] = val.location();
7523 }
7524 return param_data;
7525 } else {
7526 it.AdvanceToArgumentsFrame();
7527 frame = it.frame();
7528 int args_count = frame->ComputeParametersCount();
7529
7530 *total_argc = bound_argc + args_count;
7531 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7532 for (int i = 0; i < args_count; i++) {
7533 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7534 param_data[bound_argc + i] = val.location();
7535 }
7536 return param_data;
7537 }
7538}
7539
7540
7541RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007543 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007544 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007545 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007546
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007547 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007548 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007549 int bound_argc = 0;
7550 if (!args[1]->IsNull()) {
7551 CONVERT_ARG_CHECKED(JSArray, params, 1);
7552 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007553 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007554 bound_argc = Smi::cast(params->length())->value();
7555 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007557 int total_argc = 0;
7558 SmartPointer<Object**> param_data =
7559 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007560 for (int i = 0; i < bound_argc; i++) {
7561 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007562 param_data[i] = val.location();
7563 }
7564
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007565 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007566 Handle<Object> result =
7567 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007568 if (exception) {
7569 return Failure::Exception();
7570 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007571
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007572 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007573 return *result;
7574}
7575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007577static void TrySettingInlineConstructStub(Isolate* isolate,
7578 Handle<JSFunction> function) {
7579 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007580 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007581 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007582 }
7583 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007584 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007585 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007586 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007587 function->shared()->set_construct_stub(
7588 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007589 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007590 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007591}
7592
7593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007594RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007595 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596 ASSERT(args.length() == 1);
7597
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007598 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007599
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007600 // If the constructor isn't a proper function we throw a type error.
7601 if (!constructor->IsJSFunction()) {
7602 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7603 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007604 isolate->factory()->NewTypeError("not_constructor", arguments);
7605 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007606 }
7607
7608 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007609
7610 // If function should not have prototype, construction is not allowed. In this
7611 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007612 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007613 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7614 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007615 isolate->factory()->NewTypeError("not_constructor", arguments);
7616 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007617 }
7618
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007619#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007620 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007621 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007622 if (debug->StepInActive()) {
7623 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007624 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007625#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007626
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007627 if (function->has_initial_map()) {
7628 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629 // The 'Function' function ignores the receiver object when
7630 // called using 'new' and creates a new JSFunction object that
7631 // is returned. The receiver object is only used for error
7632 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007633 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007634 // allocate JSFunctions since it does not properly initialize
7635 // the shared part of the function. Since the receiver is
7636 // ignored anyway, we use the global object as the receiver
7637 // instead of a new JSFunction object. This way, errors are
7638 // reported the same way whether or not 'Function' is called
7639 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007640 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007642 }
7643
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007644 // The function should be compiled for the optimization hints to be
7645 // available. We cannot use EnsureCompiled because that forces a
7646 // compilation through the shared function info which makes it
7647 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007648 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007649 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007650
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007651 if (!function->has_initial_map() &&
7652 shared->IsInobjectSlackTrackingInProgress()) {
7653 // The tracking is already in progress for another function. We can only
7654 // track one initial_map at a time, so we force the completion before the
7655 // function is called as a constructor for the first time.
7656 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007657 }
7658
7659 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007660 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7661 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007662 // Delay setting the stub if inobject slack tracking is in progress.
7663 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007664 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007665 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 isolate->counters()->constructed_objects()->Increment();
7668 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007669
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007670 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671}
7672
7673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007674RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007675 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007676 ASSERT(args.length() == 1);
7677
7678 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7679 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007680 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007682 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007683}
7684
7685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007686RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007688 ASSERT(args.length() == 1);
7689
7690 Handle<JSFunction> function = args.at<JSFunction>(0);
7691#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007692 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007693 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007694 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007695 PrintF("]\n");
7696 }
7697#endif
7698
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007699 // Compile the target function. Here we compile using CompileLazyInLoop in
7700 // order to get the optimized version. This helps code like delta-blue
7701 // that calls performance-critical routines through constructors. A
7702 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7703 // direct call. Since the in-loop tracking takes place through CallICs
7704 // this means that things called through constructors are never known to
7705 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007706 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007707 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007708 return Failure::Exception();
7709 }
7710
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007711 // All done. Return the compiled code.
7712 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713 return function->code();
7714}
7715
7716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007717RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007718 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007719 ASSERT(args.length() == 1);
7720 Handle<JSFunction> function = args.at<JSFunction>(0);
7721 // If the function is not optimizable or debugger is active continue using the
7722 // code from the full compiler.
7723 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007724 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007725 if (FLAG_trace_opt) {
7726 PrintF("[failed to optimize ");
7727 function->PrintName();
7728 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7729 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007730 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007731 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007732 function->ReplaceCode(function->shared()->code());
7733 return function->code();
7734 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007735 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007736 return function->code();
7737 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007738 if (FLAG_trace_opt) {
7739 PrintF("[failed to optimize ");
7740 function->PrintName();
7741 PrintF(": optimized compilation failed]\n");
7742 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007743 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007744 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007745}
7746
7747
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007748RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007749 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007750 ASSERT(args.length() == 1);
7751 RUNTIME_ASSERT(args[0]->IsSmi());
7752 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007753 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007754 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7755 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007756 int frames = deoptimizer->output_count();
7757
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007758 deoptimizer->MaterializeHeapNumbers();
7759 delete deoptimizer;
7760
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007761 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007762 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007763 for (int i = 0; i < frames - 1; i++) it.Advance();
7764 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007765
7766 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007767 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007768 Handle<Object> arguments;
7769 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007770 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007771 if (arguments.is_null()) {
7772 // FunctionGetArguments can't throw an exception, so cast away the
7773 // doubt with an assert.
7774 arguments = Handle<Object>(
7775 Accessors::FunctionGetArguments(*function,
7776 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007777 ASSERT(*arguments != isolate->heap()->null_value());
7778 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007779 }
7780 frame->SetExpression(i, *arguments);
7781 }
7782 }
7783
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007784 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007785 if (type == Deoptimizer::EAGER) {
7786 RUNTIME_ASSERT(function->IsOptimized());
7787 } else {
7788 RUNTIME_ASSERT(!function->IsOptimized());
7789 }
7790
7791 // Avoid doing too much work when running with --always-opt and keep
7792 // the optimized code around.
7793 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007794 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007795 }
7796
7797 // Count the number of optimized activations of the function.
7798 int activations = 0;
7799 while (!it.done()) {
7800 JavaScriptFrame* frame = it.frame();
7801 if (frame->is_optimized() && frame->function() == *function) {
7802 activations++;
7803 }
7804 it.Advance();
7805 }
7806
7807 // TODO(kasperl): For now, we cannot support removing the optimized
7808 // code when we have recursive invocations of the same function.
7809 if (activations == 0) {
7810 if (FLAG_trace_deopt) {
7811 PrintF("[removing optimized code for: ");
7812 function->PrintName();
7813 PrintF("]\n");
7814 }
7815 function->ReplaceCode(function->shared()->code());
7816 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007817 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007818}
7819
7820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007821RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007822 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007823 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007825}
7826
7827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007828RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007829 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007830 ASSERT(args.length() == 1);
7831 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007832 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007833
7834 Deoptimizer::DeoptimizeFunction(*function);
7835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007836 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007837}
7838
7839
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007840RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7841#if defined(USE_SIMULATOR)
7842 return isolate->heap()->true_value();
7843#else
7844 return isolate->heap()->false_value();
7845#endif
7846}
7847
7848
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007849RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7850 HandleScope scope(isolate);
7851 ASSERT(args.length() == 1);
7852 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7853 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7854 function->MarkForLazyRecompilation();
7855 return isolate->heap()->undefined_value();
7856}
7857
7858
lrn@chromium.org1c092762011-05-09 09:42:16 +00007859RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7860 HandleScope scope(isolate);
7861 ASSERT(args.length() == 1);
7862 if (!V8::UseCrankshaft()) {
7863 return Smi::FromInt(4); // 4 == "never".
7864 }
7865 if (FLAG_always_opt) {
7866 return Smi::FromInt(3); // 3 == "always".
7867 }
7868 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7869 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7870 : Smi::FromInt(2); // 2 == "no".
7871}
7872
7873
7874RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7875 HandleScope scope(isolate);
7876 ASSERT(args.length() == 1);
7877 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7878 return Smi::FromInt(function->shared()->opt_count());
7879}
7880
7881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007882RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007883 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007884 ASSERT(args.length() == 1);
7885 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7886
7887 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007888 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007889
7890 // We have hit a back edge in an unoptimized frame for a function that was
7891 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007892 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007893 // Keep track of whether we've succeeded in optimizing.
7894 bool succeeded = unoptimized->optimizable();
7895 if (succeeded) {
7896 // If we are trying to do OSR when there are already optimized
7897 // activations of the function, it means (a) the function is directly or
7898 // indirectly recursive and (b) an optimized invocation has been
7899 // deoptimized so that we are currently in an unoptimized activation.
7900 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007901 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007902 while (succeeded && !it.done()) {
7903 JavaScriptFrame* frame = it.frame();
7904 succeeded = !frame->is_optimized() || frame->function() != *function;
7905 it.Advance();
7906 }
7907 }
7908
7909 int ast_id = AstNode::kNoNumber;
7910 if (succeeded) {
7911 // The top JS function is this one, the PC is somewhere in the
7912 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007913 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007914 JavaScriptFrame* frame = it.frame();
7915 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007916 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007917 ASSERT(unoptimized->contains(frame->pc()));
7918
7919 // Use linear search of the unoptimized code's stack check table to find
7920 // the AST id matching the PC.
7921 Address start = unoptimized->instruction_start();
7922 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007923 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007924 uint32_t table_length = Memory::uint32_at(table_cursor);
7925 table_cursor += kIntSize;
7926 for (unsigned i = 0; i < table_length; ++i) {
7927 // Table entries are (AST id, pc offset) pairs.
7928 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7929 if (pc_offset == target_pc_offset) {
7930 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7931 break;
7932 }
7933 table_cursor += 2 * kIntSize;
7934 }
7935 ASSERT(ast_id != AstNode::kNoNumber);
7936 if (FLAG_trace_osr) {
7937 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7938 function->PrintName();
7939 PrintF("]\n");
7940 }
7941
7942 // Try to compile the optimized code. A true return value from
7943 // CompileOptimized means that compilation succeeded, not necessarily
7944 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007945 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7946 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007947 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7948 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007949 if (data->OsrPcOffset()->value() >= 0) {
7950 if (FLAG_trace_osr) {
7951 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007952 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007953 }
7954 ASSERT(data->OsrAstId()->value() == ast_id);
7955 } else {
7956 // We may never generate the desired OSR entry if we emit an
7957 // early deoptimize.
7958 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007959 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007960 } else {
7961 succeeded = false;
7962 }
7963 }
7964
7965 // Revert to the original stack checks in the original unoptimized code.
7966 if (FLAG_trace_osr) {
7967 PrintF("[restoring original stack checks in ");
7968 function->PrintName();
7969 PrintF("]\n");
7970 }
7971 StackCheckStub check_stub;
7972 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007973 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007974 Deoptimizer::RevertStackCheckCode(*unoptimized,
7975 *check_code,
7976 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007977
7978 // Allow OSR only at nesting level zero again.
7979 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7980
7981 // If the optimization attempt succeeded, return the AST id tagged as a
7982 // smi. This tells the builtin that we need to translate the unoptimized
7983 // frame to an optimized one.
7984 if (succeeded) {
7985 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7986 return Smi::FromInt(ast_id);
7987 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007988 if (function->IsMarkedForLazyRecompilation()) {
7989 function->ReplaceCode(function->shared()->code());
7990 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007991 return Smi::FromInt(-1);
7992 }
7993}
7994
7995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998 ASSERT(args.length() == 1);
7999 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8000 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008006 ASSERT(args.length() == 1);
8007 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8008 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8009}
8010
8011
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008012RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008014 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015
kasper.lund7276f142008-07-30 08:49:36 +00008016 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008017 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008018 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008019 { MaybeObject* maybe_result =
8020 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008021 if (!maybe_result->ToObject(&result)) return maybe_result;
8022 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025
kasper.lund7276f142008-07-30 08:49:36 +00008026 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027}
8028
lrn@chromium.org303ada72010-10-27 09:33:13 +00008029
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008030RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8031 NoHandleAllocation ha;
8032 ASSERT(args.length() == 1);
8033 JSObject* extension_object;
8034 if (args[0]->IsJSObject()) {
8035 extension_object = JSObject::cast(args[0]);
8036 } else {
8037 // Convert the object to a proper JavaScript object.
8038 MaybeObject* maybe_js_object = args[0]->ToObject();
8039 if (!maybe_js_object->To(&extension_object)) {
8040 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8041 HandleScope scope(isolate);
8042 Handle<Object> handle = args.at<Object>(0);
8043 Handle<Object> result =
8044 isolate->factory()->NewTypeError("with_expression",
8045 HandleVector(&handle, 1));
8046 return isolate->Throw(*result);
8047 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008048 return maybe_js_object;
8049 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050 }
8051 }
8052
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008053 Context* context;
8054 MaybeObject* maybe_context =
8055 isolate->heap()->AllocateWithContext(isolate->context(),
8056 extension_object);
8057 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008058 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008059 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008060}
8061
8062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008063RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008064 NoHandleAllocation ha;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008065 ASSERT(args.length() == 2);
8066 String* name = String::cast(args[0]);
8067 Object* thrown_object = args[1];
8068 Context* context;
8069 MaybeObject* maybe_context =
8070 isolate->heap()->AllocateCatchContext(isolate->context(),
8071 name,
8072 thrown_object);
8073 if (!maybe_context->To(&context)) return maybe_context;
8074 isolate->set_context(context);
8075 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008076}
8077
8078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008079RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008080 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008081 ASSERT(args.length() == 2);
8082
8083 CONVERT_ARG_CHECKED(Context, context, 0);
8084 CONVERT_ARG_CHECKED(String, name, 1);
8085
8086 int index;
8087 PropertyAttributes attributes;
8088 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008089 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008091 // If the slot was not found the result is true.
8092 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008093 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 }
8095
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008096 // If the slot was found in a context, it should be DONT_DELETE.
8097 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008099 }
8100
8101 // The slot was found in a JSObject, either a context extension object,
8102 // the global object, or an arguments object. Try to delete it
8103 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8104 // which allows deleting all parameters in functions that mention
8105 // 'arguments', we do this even for the case of slots found on an
8106 // arguments object. The slot was found on an arguments object if the
8107 // index is non-negative.
8108 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8109 if (index >= 0) {
8110 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
8111 } else {
8112 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
8113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008114}
8115
8116
ager@chromium.orga1645e22009-09-09 19:27:10 +00008117// A mechanism to return a pair of Object pointers in registers (if possible).
8118// How this is achieved is calling convention-dependent.
8119// All currently supported x86 compiles uses calling conventions that are cdecl
8120// variants where a 64-bit value is returned in two 32-bit registers
8121// (edx:eax on ia32, r1:r0 on ARM).
8122// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8123// In Win64 calling convention, a struct of two pointers is returned in memory,
8124// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008125#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008126struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008127 MaybeObject* x;
8128 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008129};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008130
lrn@chromium.org303ada72010-10-27 09:33:13 +00008131static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008132 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008133 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8134 // In Win64 they are assigned to a hidden first argument.
8135 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008136}
8137#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008138typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008139static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008140 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008141 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008142}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008143#endif
8144
8145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008146static inline MaybeObject* Unhole(Heap* heap,
8147 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008148 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008149 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8150 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008151 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008152}
8153
8154
danno@chromium.org40cb8782011-05-25 07:58:50 +00008155static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8156 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008157 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008158 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008159 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008160 JSFunction* context_extension_function =
8161 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008162 // If the holder isn't a context extension object, we just return it
8163 // as the receiver. This allows arguments objects to be used as
8164 // receivers, but only if they are put in the context scope chain
8165 // explicitly via a with-statement.
8166 Object* constructor = holder->map()->constructor();
8167 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008168 // Fall back to using the global object as the implicit receiver if
8169 // the property turns out to be a local variable allocated in a
8170 // context extension object - introduced via eval. Implicit global
8171 // receivers are indicated with the hole value.
8172 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008173}
8174
8175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008176static ObjectPair LoadContextSlotHelper(Arguments args,
8177 Isolate* isolate,
8178 bool throw_error) {
8179 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008180 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008182 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008183 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008185 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008186 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008187
8188 int index;
8189 PropertyAttributes attributes;
8190 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008191 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008192
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008193 // If the index is non-negative, the slot has been found in a local
8194 // variable or a parameter. Read it from the context object or the
8195 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008197 // If the "property" we were looking for is a local variable or an
8198 // argument in a context, the receiver is the global object; see
8199 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008200 //
8201 // Use the hole as the receiver to signal that the receiver is
8202 // implicit and that the global receiver should be used.
8203 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008204 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008205 ? Context::cast(*holder)->get(index)
8206 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008207 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208 }
8209
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008210 // If the holder is found, we read the property from it.
8211 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008212 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008213 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008214 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008215 if (object->IsGlobalObject()) {
8216 receiver = GlobalObject::cast(object)->global_receiver();
8217 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008218 // Use the hole as the receiver to signal that the receiver is
8219 // implicit and that the global receiver should be used.
8220 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008221 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008223 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008224
8225 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008226 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008227
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008228 // No need to unhole the value here. This is taken care of by the
8229 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008230 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008231 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 }
8233
8234 if (throw_error) {
8235 // The property doesn't exist - throw exception.
8236 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237 isolate->factory()->NewReferenceError("not_defined",
8238 HandleVector(&name, 1));
8239 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008241 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 return MakePair(isolate->heap()->undefined_value(),
8243 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244 }
8245}
8246
8247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008248RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250}
8251
8252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008253RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255}
8256
8257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008258RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008260 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008264 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008265 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008266 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8267 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008268 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269
8270 int index;
8271 PropertyAttributes attributes;
8272 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008273 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008274
8275 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008276 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008277 // Ignore if read_only variable.
8278 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008279 // Context is a fixed array and set cannot fail.
8280 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008281 } else if (strict_mode == kStrictMode) {
8282 // Setting read only property in strict mode.
8283 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 isolate->factory()->NewTypeError("strict_cannot_assign",
8285 HandleVector(&name, 1));
8286 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008287 }
8288 } else {
8289 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008290 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008291 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008292 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008294 return Failure::Exception();
8295 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296 }
8297 return *value;
8298 }
8299
8300 // Slow case: The property is not in a FixedArray context.
8301 // It is either in an JSObject extension context or it was not found.
8302 Handle<JSObject> context_ext;
8303
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008304 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008306 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008307 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008308 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008309 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008310
8311 if (strict_mode == kStrictMode) {
8312 // Throw in strict mode (assignment to undefined variable).
8313 Handle<Object> error =
8314 isolate->factory()->NewReferenceError(
8315 "not_defined", HandleVector(&name, 1));
8316 return isolate->Throw(*error);
8317 }
8318 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 }
8322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008323 // Set the property, but ignore if read_only variable on the context
8324 // extension object itself.
8325 if ((attributes & READ_ONLY) == 0 ||
8326 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008327 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008328 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008329 SetProperty(context_ext, name, value, NONE, strict_mode));
8330 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008331 // Setting read only property in strict mode.
8332 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008333 isolate->factory()->NewTypeError(
8334 "strict_cannot_assign", HandleVector(&name, 1));
8335 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008336 }
8337 return *value;
8338}
8339
8340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008341RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008342 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008343 ASSERT(args.length() == 1);
8344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008346}
8347
8348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008349RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008350 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008351 ASSERT(args.length() == 1);
8352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008353 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354}
8355
8356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008357RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008358 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008359 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008360}
8361
8362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008363RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008364 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 ASSERT(args.length() == 1);
8366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008367 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008368 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008369 isolate->factory()->NewReferenceError("not_defined",
8370 HandleVector(&name, 1));
8371 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008372}
8373
8374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008375RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008376 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377
8378 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008379 if (isolate->stack_guard()->IsStackOverflow()) {
8380 NoHandleAllocation na;
8381 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008382 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008383
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008384 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008385}
8386
8387
8388// NOTE: These PrintXXX functions are defined for all builds (not just
8389// DEBUG builds) because we may want to be able to trace function
8390// calls in all modes.
8391static void PrintString(String* str) {
8392 // not uncommon to have empty strings
8393 if (str->length() > 0) {
8394 SmartPointer<char> s =
8395 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8396 PrintF("%s", *s);
8397 }
8398}
8399
8400
8401static void PrintObject(Object* obj) {
8402 if (obj->IsSmi()) {
8403 PrintF("%d", Smi::cast(obj)->value());
8404 } else if (obj->IsString() || obj->IsSymbol()) {
8405 PrintString(String::cast(obj));
8406 } else if (obj->IsNumber()) {
8407 PrintF("%g", obj->Number());
8408 } else if (obj->IsFailure()) {
8409 PrintF("<failure>");
8410 } else if (obj->IsUndefined()) {
8411 PrintF("<undefined>");
8412 } else if (obj->IsNull()) {
8413 PrintF("<null>");
8414 } else if (obj->IsTrue()) {
8415 PrintF("<true>");
8416 } else if (obj->IsFalse()) {
8417 PrintF("<false>");
8418 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008419 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008420 }
8421}
8422
8423
8424static int StackSize() {
8425 int n = 0;
8426 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8427 return n;
8428}
8429
8430
8431static void PrintTransition(Object* result) {
8432 // indentation
8433 { const int nmax = 80;
8434 int n = StackSize();
8435 if (n <= nmax)
8436 PrintF("%4d:%*s", n, n, "");
8437 else
8438 PrintF("%4d:%*s", n, nmax, "...");
8439 }
8440
8441 if (result == NULL) {
8442 // constructor calls
8443 JavaScriptFrameIterator it;
8444 JavaScriptFrame* frame = it.frame();
8445 if (frame->IsConstructor()) PrintF("new ");
8446 // function name
8447 Object* fun = frame->function();
8448 if (fun->IsJSFunction()) {
8449 PrintObject(JSFunction::cast(fun)->shared()->name());
8450 } else {
8451 PrintObject(fun);
8452 }
8453 // function arguments
8454 // (we are intentionally only printing the actually
8455 // supplied parameters, not all parameters required)
8456 PrintF("(this=");
8457 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008458 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008459 for (int i = 0; i < length; i++) {
8460 PrintF(", ");
8461 PrintObject(frame->GetParameter(i));
8462 }
8463 PrintF(") {\n");
8464
8465 } else {
8466 // function result
8467 PrintF("} -> ");
8468 PrintObject(result);
8469 PrintF("\n");
8470 }
8471}
8472
8473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008474RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008475 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008476 NoHandleAllocation ha;
8477 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008479}
8480
8481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008482RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008483 NoHandleAllocation ha;
8484 PrintTransition(args[0]);
8485 return args[0]; // return TOS
8486}
8487
8488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008489RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490 NoHandleAllocation ha;
8491 ASSERT(args.length() == 1);
8492
8493#ifdef DEBUG
8494 if (args[0]->IsString()) {
8495 // If we have a string, assume it's a code "marker"
8496 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008497 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008498 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008499 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8500 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008501 } else {
8502 PrintF("DebugPrint: ");
8503 }
8504 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008505 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008506 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008507 HeapObject::cast(args[0])->map()->Print();
8508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008510 // ShortPrint is available in release mode. Print is not.
8511 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512#endif
8513 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008514 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008515
8516 return args[0]; // return TOS
8517}
8518
8519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008520RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008521 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008522 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008523 isolate->PrintStack();
8524 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008525}
8526
8527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008528RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008530 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008531
8532 // According to ECMA-262, section 15.9.1, page 117, the precision of
8533 // the number in a Date object representing a particular instant in
8534 // time is milliseconds. Therefore, we floor the result of getting
8535 // the OS time.
8536 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008537 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538}
8539
8540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008541RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008542 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008543 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008545 CONVERT_ARG_CHECKED(String, str, 0);
8546 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008548 CONVERT_ARG_CHECKED(JSArray, output, 1);
8549 RUNTIME_ASSERT(output->HasFastElements());
8550
8551 AssertNoAllocation no_allocation;
8552
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008553 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008554 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8555 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008556 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008557 result = DateParser::Parse(str->ToAsciiVector(),
8558 output_array,
8559 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008560 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008561 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008562 result = DateParser::Parse(str->ToUC16Vector(),
8563 output_array,
8564 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008565 }
8566
8567 if (result) {
8568 return *output;
8569 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571 }
8572}
8573
8574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008575RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576 NoHandleAllocation ha;
8577 ASSERT(args.length() == 1);
8578
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008579 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008580 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008581 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008582}
8583
8584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008585RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008586 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008587 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008589 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590}
8591
8592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008593RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594 NoHandleAllocation ha;
8595 ASSERT(args.length() == 1);
8596
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008597 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008598 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599}
8600
8601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008602RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008603 ASSERT(args.length() == 1);
8604 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008605 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008606 return JSGlobalObject::cast(global)->global_receiver();
8607}
8608
8609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008610RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008612 ASSERT_EQ(1, args.length());
8613 CONVERT_ARG_CHECKED(String, source, 0);
8614
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008615 source = Handle<String>(source->TryFlattenGetString());
8616 // Optimized fast case where we only have ascii characters.
8617 Handle<Object> result;
8618 if (source->IsSeqAsciiString()) {
8619 result = JsonParser<true>::Parse(source);
8620 } else {
8621 result = JsonParser<false>::Parse(source);
8622 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008623 if (result.is_null()) {
8624 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008625 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008626 return Failure::Exception();
8627 }
8628 return *result;
8629}
8630
8631
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008632bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8633 Handle<Context> context) {
8634 if (context->allow_code_gen_from_strings()->IsFalse()) {
8635 // Check with callback if set.
8636 AllowCodeGenerationFromStringsCallback callback =
8637 isolate->allow_code_gen_callback();
8638 if (callback == NULL) {
8639 // No callback set and code generation disallowed.
8640 return false;
8641 } else {
8642 // Callback set. Let it decide if code generation is allowed.
8643 VMState state(isolate, EXTERNAL);
8644 return callback(v8::Utils::ToLocal(context));
8645 }
8646 }
8647 return true;
8648}
8649
8650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008651RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008652 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008653 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008654 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008655
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008656 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008657 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008658
8659 // Check if global context allows code generation from
8660 // strings. Throw an exception if it doesn't.
8661 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8662 return isolate->Throw(*isolate->factory()->NewError(
8663 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8664 }
8665
8666 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008667 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8668 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008669 true,
8670 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008671 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008672 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8674 context,
8675 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676 return *fun;
8677}
8678
8679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680static ObjectPair CompileGlobalEval(Isolate* isolate,
8681 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008682 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008683 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008684 Handle<Context> context = Handle<Context>(isolate->context());
8685 Handle<Context> global_context = Handle<Context>(context->global_context());
8686
8687 // Check if global context allows code generation from
8688 // strings. Throw an exception if it doesn't.
8689 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8690 isolate->Throw(*isolate->factory()->NewError(
8691 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8692 return MakePair(Failure::Exception(), NULL);
8693 }
8694
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008695 // Deal with a normal eval call with a string argument. Compile it
8696 // and return the compiled function bound in the local context.
8697 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8698 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008699 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008700 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008701 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008702 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703 Handle<JSFunction> compiled =
8704 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008705 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008706 return MakePair(*compiled, *receiver);
8707}
8708
8709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008710RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008711 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008712
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008714 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008715 Handle<Object> receiver; // Will be overwritten.
8716
8717 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008718 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008719#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008720 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008721 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008722 StackFrameLocator locator;
8723 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008724 ASSERT(Context::cast(frame->context()) == *context);
8725#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008726
8727 // Find where the 'eval' symbol is bound. It is unaliased only if
8728 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008729 int index = -1;
8730 PropertyAttributes attributes = ABSENT;
8731 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008732 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8733 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008734 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008735 // Stop search when eval is found or when the global context is
8736 // reached.
8737 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008738 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008739 }
8740
iposva@chromium.org245aa852009-02-10 00:49:54 +00008741 // If eval could not be resolved, it has been deleted and we need to
8742 // throw a reference error.
8743 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008744 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008745 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008746 isolate->factory()->NewReferenceError("not_defined",
8747 HandleVector(&name, 1));
8748 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008749 }
8750
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008751 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008752 // 'eval' is not bound in the global context. Just call the function
8753 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008754 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008755 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008756 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008757 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008758 }
8759
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008760 // 'eval' is bound in the global context, but it may have been overwritten.
8761 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008762 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008763 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008764 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008765 }
8766
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008767 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008768 return CompileGlobalEval(isolate,
8769 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008770 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008771 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008772}
8773
8774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008775RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008776 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008779 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008780
8781 // 'eval' is bound in the global context, but it may have been overwritten.
8782 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008783 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008784 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008785 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008786 }
8787
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008788 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008789 return CompileGlobalEval(isolate,
8790 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008791 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008792 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008793}
8794
8795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008796RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797 // This utility adjusts the property attributes for newly created Function
8798 // object ("new Function(...)") by changing the map.
8799 // All it does is changing the prototype property to enumerable
8800 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008801 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802 ASSERT(args.length() == 1);
8803 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804
8805 Handle<Map> map = func->shared()->strict_mode()
8806 ? isolate->strict_mode_function_instance_map()
8807 : isolate->function_instance_map();
8808
8809 ASSERT(func->map()->instance_type() == map->instance_type());
8810 ASSERT(func->map()->instance_size() == map->instance_size());
8811 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812 return *func;
8813}
8814
8815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008816RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008817 // Allocate a block of memory in NewSpace (filled with a filler).
8818 // Use as fallback for allocation in generated code when NewSpace
8819 // is full.
8820 ASSERT(args.length() == 1);
8821 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8822 int size = size_smi->value();
8823 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8824 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008825 Heap* heap = isolate->heap();
8826 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008827 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008828 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008829 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008830 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008831 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008832 }
8833 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008834 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008835}
8836
8837
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008838// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008839// array. Returns true if the element was pushed on the stack and
8840// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008841RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008842 ASSERT(args.length() == 2);
8843 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008844 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008845 RUNTIME_ASSERT(array->HasFastElements());
8846 int length = Smi::cast(array->length())->value();
8847 FixedArray* elements = FixedArray::cast(array->elements());
8848 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008849 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008850 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008851 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008852 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008853 { MaybeObject* maybe_obj =
8854 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008855 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8856 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008857 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008858}
8859
8860
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008861/**
8862 * A simple visitor visits every element of Array's.
8863 * The backend storage can be a fixed array for fast elements case,
8864 * or a dictionary for sparse array. Since Dictionary is a subtype
8865 * of FixedArray, the class can be used by both fast and slow cases.
8866 * The second parameter of the constructor, fast_elements, specifies
8867 * whether the storage is a FixedArray or Dictionary.
8868 *
8869 * An index limit is used to deal with the situation that a result array
8870 * length overflows 32-bit non-negative integer.
8871 */
8872class ArrayConcatVisitor {
8873 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 ArrayConcatVisitor(Isolate* isolate,
8875 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008876 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008877 isolate_(isolate),
8878 storage_(Handle<FixedArray>::cast(
8879 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008880 index_offset_(0u),
8881 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008882
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008883 ~ArrayConcatVisitor() {
8884 clear_storage();
8885 }
8886
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008887 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008888 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008889 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008890
8891 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008892 if (index < static_cast<uint32_t>(storage_->length())) {
8893 storage_->set(index, *elm);
8894 return;
8895 }
8896 // Our initial estimate of length was foiled, possibly by
8897 // getters on the arrays increasing the length of later arrays
8898 // during iteration.
8899 // This shouldn't happen in anything but pathological cases.
8900 SetDictionaryMode(index);
8901 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008902 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008903 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008904 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008905 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008906 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008907 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008908 // Dictionary needed to grow.
8909 clear_storage();
8910 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008911 }
8912}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008913
8914 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008915 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8916 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008917 } else {
8918 index_offset_ += delta;
8919 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008920 }
8921
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008922 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008923 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008924 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008926 Handle<Map> map;
8927 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008928 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008930 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008931 }
8932 array->set_map(*map);
8933 array->set_length(*length);
8934 array->set_elements(*storage_);
8935 return array;
8936 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008937
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008938 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008939 // Convert storage to dictionary mode.
8940 void SetDictionaryMode(uint32_t index) {
8941 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008942 Handle<FixedArray> current_storage(*storage_);
8943 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008944 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008945 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8946 for (uint32_t i = 0; i < current_length; i++) {
8947 HandleScope loop_scope;
8948 Handle<Object> element(current_storage->get(i));
8949 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008950 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008951 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008952 if (!new_storage.is_identical_to(slow_storage)) {
8953 slow_storage = loop_scope.CloseAndEscape(new_storage);
8954 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008955 }
8956 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008957 clear_storage();
8958 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008959 fast_elements_ = false;
8960 }
8961
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008962 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008963 isolate_->global_handles()->Destroy(
8964 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008965 }
8966
8967 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008968 storage_ = Handle<FixedArray>::cast(
8969 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008970 }
8971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008973 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008974 // Index after last seen index. Always less than or equal to
8975 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008976 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008977 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008978};
8979
8980
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008981static uint32_t EstimateElementCount(Handle<JSArray> array) {
8982 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8983 int element_count = 0;
8984 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008985 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008986 // Fast elements can't have lengths that are not representable by
8987 // a 32-bit signed integer.
8988 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8989 int fast_length = static_cast<int>(length);
8990 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8991 for (int i = 0; i < fast_length; i++) {
8992 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008993 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008994 break;
8995 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008996 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008997 Handle<NumberDictionary> dictionary(
8998 NumberDictionary::cast(array->elements()));
8999 int capacity = dictionary->Capacity();
9000 for (int i = 0; i < capacity; i++) {
9001 Handle<Object> key(dictionary->KeyAt(i));
9002 if (dictionary->IsKey(*key)) {
9003 element_count++;
9004 }
9005 }
9006 break;
9007 }
9008 default:
9009 // External arrays are always dense.
9010 return length;
9011 }
9012 // As an estimate, we assume that the prototype doesn't contain any
9013 // inherited elements.
9014 return element_count;
9015}
9016
9017
9018
9019template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009020static void IterateExternalArrayElements(Isolate* isolate,
9021 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009022 bool elements_are_ints,
9023 bool elements_are_guaranteed_smis,
9024 ArrayConcatVisitor* visitor) {
9025 Handle<ExternalArrayClass> array(
9026 ExternalArrayClass::cast(receiver->elements()));
9027 uint32_t len = static_cast<uint32_t>(array->length());
9028
9029 ASSERT(visitor != NULL);
9030 if (elements_are_ints) {
9031 if (elements_are_guaranteed_smis) {
9032 for (uint32_t j = 0; j < len; j++) {
9033 HandleScope loop_scope;
9034 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9035 visitor->visit(j, e);
9036 }
9037 } else {
9038 for (uint32_t j = 0; j < len; j++) {
9039 HandleScope loop_scope;
9040 int64_t val = static_cast<int64_t>(array->get(j));
9041 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9042 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9043 visitor->visit(j, e);
9044 } else {
9045 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009046 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009047 visitor->visit(j, e);
9048 }
9049 }
9050 }
9051 } else {
9052 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 HandleScope loop_scope(isolate);
9054 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009055 visitor->visit(j, e);
9056 }
9057 }
9058}
9059
9060
9061// Used for sorting indices in a List<uint32_t>.
9062static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9063 uint32_t a = *ap;
9064 uint32_t b = *bp;
9065 return (a == b) ? 0 : (a < b) ? -1 : 1;
9066}
9067
9068
9069static void CollectElementIndices(Handle<JSObject> object,
9070 uint32_t range,
9071 List<uint32_t>* indices) {
9072 JSObject::ElementsKind kind = object->GetElementsKind();
9073 switch (kind) {
9074 case JSObject::FAST_ELEMENTS: {
9075 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9076 uint32_t length = static_cast<uint32_t>(elements->length());
9077 if (range < length) length = range;
9078 for (uint32_t i = 0; i < length; i++) {
9079 if (!elements->get(i)->IsTheHole()) {
9080 indices->Add(i);
9081 }
9082 }
9083 break;
9084 }
9085 case JSObject::DICTIONARY_ELEMENTS: {
9086 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009087 uint32_t capacity = dict->Capacity();
9088 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009089 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009090 Handle<Object> k(dict->KeyAt(j));
9091 if (dict->IsKey(*k)) {
9092 ASSERT(k->IsNumber());
9093 uint32_t index = static_cast<uint32_t>(k->Number());
9094 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009095 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009096 }
9097 }
9098 }
9099 break;
9100 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009101 default: {
9102 int dense_elements_length;
9103 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009104 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009105 dense_elements_length =
9106 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009107 break;
9108 }
9109 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009110 dense_elements_length =
9111 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009112 break;
9113 }
9114 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009115 dense_elements_length =
9116 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009117 break;
9118 }
9119 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009120 dense_elements_length =
9121 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009122 break;
9123 }
9124 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009125 dense_elements_length =
9126 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009127 break;
9128 }
9129 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009130 dense_elements_length =
9131 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009132 break;
9133 }
9134 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009135 dense_elements_length =
9136 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009137 break;
9138 }
9139 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009140 dense_elements_length =
9141 ExternalFloatArray::cast(object->elements())->length();
9142 break;
9143 }
9144 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9145 dense_elements_length =
9146 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009147 break;
9148 }
9149 default:
9150 UNREACHABLE();
9151 dense_elements_length = 0;
9152 break;
9153 }
9154 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9155 if (range <= length) {
9156 length = range;
9157 // We will add all indices, so we might as well clear it first
9158 // and avoid duplicates.
9159 indices->Clear();
9160 }
9161 for (uint32_t i = 0; i < length; i++) {
9162 indices->Add(i);
9163 }
9164 if (length == range) return; // All indices accounted for already.
9165 break;
9166 }
9167 }
9168
9169 Handle<Object> prototype(object->GetPrototype());
9170 if (prototype->IsJSObject()) {
9171 // The prototype will usually have no inherited element indices,
9172 // but we have to check.
9173 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9174 }
9175}
9176
9177
9178/**
9179 * A helper function that visits elements of a JSArray in numerical
9180 * order.
9181 *
9182 * The visitor argument called for each existing element in the array
9183 * with the element index and the element's value.
9184 * Afterwards it increments the base-index of the visitor by the array
9185 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009186 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009187 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188static bool IterateElements(Isolate* isolate,
9189 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009190 ArrayConcatVisitor* visitor) {
9191 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9192 switch (receiver->GetElementsKind()) {
9193 case JSObject::FAST_ELEMENTS: {
9194 // Run through the elements FixedArray and use HasElement and GetElement
9195 // to check the prototype for missing elements.
9196 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9197 int fast_length = static_cast<int>(length);
9198 ASSERT(fast_length <= elements->length());
9199 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 HandleScope loop_scope(isolate);
9201 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009202 if (!element_value->IsTheHole()) {
9203 visitor->visit(j, element_value);
9204 } else if (receiver->HasElement(j)) {
9205 // Call GetElement on receiver, not its prototype, or getters won't
9206 // have the correct receiver.
9207 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009208 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009209 visitor->visit(j, element_value);
9210 }
9211 }
9212 break;
9213 }
9214 case JSObject::DICTIONARY_ELEMENTS: {
9215 Handle<NumberDictionary> dict(receiver->element_dictionary());
9216 List<uint32_t> indices(dict->Capacity() / 2);
9217 // Collect all indices in the object and the prototypes less
9218 // than length. This might introduce duplicates in the indices list.
9219 CollectElementIndices(receiver, length, &indices);
9220 indices.Sort(&compareUInt32);
9221 int j = 0;
9222 int n = indices.length();
9223 while (j < n) {
9224 HandleScope loop_scope;
9225 uint32_t index = indices[j];
9226 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009227 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009228 visitor->visit(index, element);
9229 // Skip to next different index (i.e., omit duplicates).
9230 do {
9231 j++;
9232 } while (j < n && indices[j] == index);
9233 }
9234 break;
9235 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009236 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9237 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9238 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009239 for (uint32_t j = 0; j < length; j++) {
9240 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9241 visitor->visit(j, e);
9242 }
9243 break;
9244 }
9245 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9246 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009248 break;
9249 }
9250 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9251 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009253 break;
9254 }
9255 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9256 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009258 break;
9259 }
9260 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9261 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009262 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009263 break;
9264 }
9265 case JSObject::EXTERNAL_INT_ELEMENTS: {
9266 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009267 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009268 break;
9269 }
9270 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9271 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009272 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009273 break;
9274 }
9275 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9276 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009277 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009278 break;
9279 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009280 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9281 IterateExternalArrayElements<ExternalDoubleArray, double>(
9282 isolate, receiver, false, false, visitor);
9283 break;
9284 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009285 default:
9286 UNREACHABLE();
9287 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009288 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009289 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009290 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009291}
9292
9293
9294/**
9295 * Array::concat implementation.
9296 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009297 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009298 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009299 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009300RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009301 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009303
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009304 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9305 int argument_count = static_cast<int>(arguments->length()->Number());
9306 RUNTIME_ASSERT(arguments->HasFastElements());
9307 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009308
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009309 // Pass 1: estimate the length and number of elements of the result.
9310 // The actual length can be larger if any of the arguments have getters
9311 // that mutate other arguments (but will otherwise be precise).
9312 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009313
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009314 uint32_t estimate_result_length = 0;
9315 uint32_t estimate_nof_elements = 0;
9316 {
9317 for (int i = 0; i < argument_count; i++) {
9318 HandleScope loop_scope;
9319 Handle<Object> obj(elements->get(i));
9320 uint32_t length_estimate;
9321 uint32_t element_estimate;
9322 if (obj->IsJSArray()) {
9323 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9324 length_estimate =
9325 static_cast<uint32_t>(array->length()->Number());
9326 element_estimate =
9327 EstimateElementCount(array);
9328 } else {
9329 length_estimate = 1;
9330 element_estimate = 1;
9331 }
9332 // Avoid overflows by capping at kMaxElementCount.
9333 if (JSObject::kMaxElementCount - estimate_result_length <
9334 length_estimate) {
9335 estimate_result_length = JSObject::kMaxElementCount;
9336 } else {
9337 estimate_result_length += length_estimate;
9338 }
9339 if (JSObject::kMaxElementCount - estimate_nof_elements <
9340 element_estimate) {
9341 estimate_nof_elements = JSObject::kMaxElementCount;
9342 } else {
9343 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009344 }
9345 }
9346 }
9347
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009348 // If estimated number of elements is more than half of length, a
9349 // fixed array (fast case) is more time and space-efficient than a
9350 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009351 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009352
9353 Handle<FixedArray> storage;
9354 if (fast_case) {
9355 // The backing storage array must have non-existing elements to
9356 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 storage = isolate->factory()->NewFixedArrayWithHoles(
9358 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009359 } else {
9360 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9361 uint32_t at_least_space_for = estimate_nof_elements +
9362 (estimate_nof_elements >> 2);
9363 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009364 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009365 }
9366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009368
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009369 for (int i = 0; i < argument_count; i++) {
9370 Handle<Object> obj(elements->get(i));
9371 if (obj->IsJSArray()) {
9372 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009373 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009374 return Failure::Exception();
9375 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009376 } else {
9377 visitor.visit(0, obj);
9378 visitor.increase_index_offset(1);
9379 }
9380 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009381
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009382 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009383}
9384
9385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386// This will not allocate (flatten the string), but it may run
9387// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009388RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 NoHandleAllocation ha;
9390 ASSERT(args.length() == 1);
9391
9392 CONVERT_CHECKED(String, string, args[0]);
9393 StringInputBuffer buffer(string);
9394 while (buffer.has_more()) {
9395 uint16_t character = buffer.GetNext();
9396 PrintF("%c", character);
9397 }
9398 return string;
9399}
9400
ager@chromium.org5ec48922009-05-05 07:25:34 +00009401// Moves all own elements of an object, that are below a limit, to positions
9402// starting at zero. All undefined values are placed after non-undefined values,
9403// and are followed by non-existing element. Does not change the length
9404// property.
9405// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009406RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009407 ASSERT(args.length() == 2);
9408 CONVERT_CHECKED(JSObject, object, args[0]);
9409 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9410 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411}
9412
9413
9414// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009415RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416 ASSERT(args.length() == 2);
9417 CONVERT_CHECKED(JSArray, from, args[0]);
9418 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009419 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009420 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009421 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9422 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009423 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009424 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009425 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009426 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009427 Object* new_map;
9428 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009429 to->set_map(Map::cast(new_map));
9430 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009431 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009432 Object* obj;
9433 { MaybeObject* maybe_obj = from->ResetElements();
9434 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9435 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009436 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009437 return to;
9438}
9439
9440
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009441// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009442RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009443 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009444 CONVERT_CHECKED(JSObject, object, args[0]);
9445 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009446 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009447 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009448 } else if (object->IsJSArray()) {
9449 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009451 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009452 }
9453}
9454
9455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009456RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009458
9459 ASSERT_EQ(3, args.length());
9460
ager@chromium.orgac091b72010-05-05 07:34:42 +00009461 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009462 Handle<Object> key1 = args.at<Object>(1);
9463 Handle<Object> key2 = args.at<Object>(2);
9464
9465 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009466 if (!key1->ToArrayIndex(&index1)
9467 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009469 }
9470
ager@chromium.orgac091b72010-05-05 07:34:42 +00009471 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9472 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009473 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009474 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009477 RETURN_IF_EMPTY_HANDLE(isolate,
9478 SetElement(jsobject, index1, tmp2, kStrictMode));
9479 RETURN_IF_EMPTY_HANDLE(isolate,
9480 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009483}
9484
9485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009487// might have elements. Can either return keys (positive integers) or
9488// intervals (pair of a negative integer (-start-1) followed by a
9489// positive (length)) or undefined values.
9490// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009491RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009494 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009495 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009496 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497 // Create an array and get all the keys into it, then remove all the
9498 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009499 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009500 int keys_length = keys->length();
9501 for (int i = 0; i < keys_length; i++) {
9502 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009503 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009504 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009505 // Zap invalid keys.
9506 keys->set_undefined(i);
9507 }
9508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009509 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009511 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009512 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009514 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009515 uint32_t actual_length =
9516 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009517 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009519 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522 }
9523}
9524
9525
9526// DefineAccessor takes an optional final argument which is the
9527// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9528// to the way accessors are implemented, it is set for both the getter
9529// and setter on the first call to DefineAccessor and ignored on
9530// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009531RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009532 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9533 // Compute attributes.
9534 PropertyAttributes attributes = NONE;
9535 if (args.length() == 5) {
9536 CONVERT_CHECKED(Smi, attrs, args[4]);
9537 int value = attrs->value();
9538 // Only attribute bits should be set.
9539 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9540 attributes = static_cast<PropertyAttributes>(value);
9541 }
9542
9543 CONVERT_CHECKED(JSObject, obj, args[0]);
9544 CONVERT_CHECKED(String, name, args[1]);
9545 CONVERT_CHECKED(Smi, flag, args[2]);
9546 CONVERT_CHECKED(JSFunction, fun, args[3]);
9547 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9548}
9549
9550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009551RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009552 ASSERT(args.length() == 3);
9553 CONVERT_CHECKED(JSObject, obj, args[0]);
9554 CONVERT_CHECKED(String, name, args[1]);
9555 CONVERT_CHECKED(Smi, flag, args[2]);
9556 return obj->LookupAccessor(name, flag->value() == 0);
9557}
9558
9559
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009560#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009561RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009562 ASSERT(args.length() == 0);
9563 return Execution::DebugBreakHelper();
9564}
9565
9566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009567// Helper functions for wrapping and unwrapping stack frame ids.
9568static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009569 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009570 return Smi::FromInt(id >> 2);
9571}
9572
9573
9574static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9575 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9576}
9577
9578
9579// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009580// args[0]: debug event listener function to set or null or undefined for
9581// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009582// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009583RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009584 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009585 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9586 args[0]->IsUndefined() ||
9587 args[0]->IsNull());
9588 Handle<Object> callback = args.at<Object>(0);
9589 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009592 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593}
9594
9595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009596RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009597 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009598 isolate->stack_guard()->DebugBreak();
9599 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009600}
9601
9602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009603static MaybeObject* DebugLookupResultValue(Heap* heap,
9604 Object* receiver,
9605 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009606 LookupResult* result,
9607 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009608 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009609 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009610 case NORMAL:
9611 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009612 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009613 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 }
9615 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009616 case FIELD:
9617 value =
9618 JSObject::cast(
9619 result->holder())->FastPropertyAt(result->GetFieldIndex());
9620 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009622 }
9623 return value;
9624 case CONSTANT_FUNCTION:
9625 return result->GetConstantFunction();
9626 case CALLBACKS: {
9627 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009628 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009629 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009630 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009631 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009632 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009633 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634 maybe_value = heap->isolate()->pending_exception();
9635 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009636 if (caught_exception != NULL) {
9637 *caught_exception = true;
9638 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009639 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009640 }
9641 return value;
9642 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009643 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009644 }
9645 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009646 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009647 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009648 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009649 case CONSTANT_TRANSITION:
9650 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652 default:
9653 UNREACHABLE();
9654 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009655 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009656 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009657}
9658
9659
ager@chromium.org32912102009-01-16 10:38:43 +00009660// Get debugger related details for an object property.
9661// args[0]: object holding property
9662// args[1]: name of the property
9663//
9664// The array returned contains the following information:
9665// 0: Property value
9666// 1: Property details
9667// 2: Property value is exception
9668// 3: Getter function if defined
9669// 4: Setter function if defined
9670// Items 2-4 are only filled if the property has either a getter or a setter
9671// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009672RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009673 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674
9675 ASSERT(args.length() == 2);
9676
9677 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9678 CONVERT_ARG_CHECKED(String, name, 1);
9679
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009680 // Make sure to set the current context to the context before the debugger was
9681 // entered (if the debugger is entered). The reason for switching context here
9682 // is that for some property lookups (accessors and interceptors) callbacks
9683 // into the embedding application can occour, and the embedding application
9684 // could have the assumption that its own global context is the current
9685 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009686 SaveContext save(isolate);
9687 if (isolate->debug()->InDebugger()) {
9688 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009689 }
9690
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009691 // Skip the global proxy as it has no properties and always delegates to the
9692 // real global object.
9693 if (obj->IsJSGlobalProxy()) {
9694 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9695 }
9696
9697
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698 // Check if the name is trivially convertible to an index and get the element
9699 // if so.
9700 uint32_t index;
9701 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009702 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009703 Object* element_or_char;
9704 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009706 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9707 return maybe_element_or_char;
9708 }
9709 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009710 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009713 }
9714
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009715 // Find the number of objects making up this.
9716 int length = LocalPrototypeChainLength(*obj);
9717
9718 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009719 Handle<JSObject> jsproto = obj;
9720 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009721 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009722 jsproto->LocalLookup(*name, &result);
9723 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009724 // LookupResult is not GC safe as it holds raw object pointers.
9725 // GC can happen later in this code so put the required fields into
9726 // local variables using handles when required for later use.
9727 PropertyType result_type = result.type();
9728 Handle<Object> result_callback_obj;
9729 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009730 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9731 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009732 }
9733 Smi* property_details = result.GetPropertyDetails().AsSmi();
9734 // DebugLookupResultValue can cause GC so details from LookupResult needs
9735 // to be copied to handles before this.
9736 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009737 Object* raw_value;
9738 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 DebugLookupResultValue(isolate->heap(), *obj, *name,
9740 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009741 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9742 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009744
9745 // If the callback object is a fixed array then it contains JavaScript
9746 // getter and/or setter.
9747 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9748 result_callback_obj->IsFixedArray();
9749 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009750 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009751 details->set(0, *value);
9752 details->set(1, property_details);
9753 if (hasJavaScriptAccessors) {
9754 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009755 caught_exception ? isolate->heap()->true_value()
9756 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009757 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9758 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9759 }
9760
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009761 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009762 }
9763 if (i < length - 1) {
9764 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9765 }
9766 }
9767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009768 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769}
9770
9771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009772RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774
9775 ASSERT(args.length() == 2);
9776
9777 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9778 CONVERT_ARG_CHECKED(String, name, 1);
9779
9780 LookupResult result;
9781 obj->Lookup(*name, &result);
9782 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009783 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009784 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009785 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009786}
9787
9788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789// Return the property type calculated from the property details.
9790// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009791RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792 ASSERT(args.length() == 1);
9793 CONVERT_CHECKED(Smi, details, args[0]);
9794 PropertyType type = PropertyDetails(details).type();
9795 return Smi::FromInt(static_cast<int>(type));
9796}
9797
9798
9799// Return the property attribute calculated from the property details.
9800// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009801RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802 ASSERT(args.length() == 1);
9803 CONVERT_CHECKED(Smi, details, args[0]);
9804 PropertyAttributes attributes = PropertyDetails(details).attributes();
9805 return Smi::FromInt(static_cast<int>(attributes));
9806}
9807
9808
9809// Return the property insertion index calculated from the property details.
9810// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009811RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812 ASSERT(args.length() == 1);
9813 CONVERT_CHECKED(Smi, details, args[0]);
9814 int index = PropertyDetails(details).index();
9815 return Smi::FromInt(index);
9816}
9817
9818
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009819// Return property value from named interceptor.
9820// args[0]: object
9821// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009822RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009823 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009824 ASSERT(args.length() == 2);
9825 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9826 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9827 CONVERT_ARG_CHECKED(String, name, 1);
9828
9829 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009830 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009831}
9832
9833
9834// Return element value from indexed interceptor.
9835// args[0]: object
9836// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009837RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009838 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 ASSERT(args.length() == 2);
9840 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9841 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9842 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9843
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009844 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009845}
9846
9847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009848RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009849 ASSERT(args.length() >= 1);
9850 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009851 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009852 if (isolate->debug()->break_id() == 0 ||
9853 break_id != isolate->debug()->break_id()) {
9854 return isolate->Throw(
9855 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 }
9857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009858 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859}
9860
9861
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009862RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009863 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009864 ASSERT(args.length() == 1);
9865
9866 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009867 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009868 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9869 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009870 if (!maybe_result->ToObject(&result)) return maybe_result;
9871 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872
9873 // Count all frames which are relevant to debugging stack trace.
9874 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009875 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009876 if (id == StackFrame::NO_ID) {
9877 // If there is no JavaScript stack frame count is 0.
9878 return Smi::FromInt(0);
9879 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009880 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009881 return Smi::FromInt(n);
9882}
9883
9884
9885static const int kFrameDetailsFrameIdIndex = 0;
9886static const int kFrameDetailsReceiverIndex = 1;
9887static const int kFrameDetailsFunctionIndex = 2;
9888static const int kFrameDetailsArgumentCountIndex = 3;
9889static const int kFrameDetailsLocalCountIndex = 4;
9890static const int kFrameDetailsSourcePositionIndex = 5;
9891static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009892static const int kFrameDetailsAtReturnIndex = 7;
9893static const int kFrameDetailsDebuggerFrameIndex = 8;
9894static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895
9896// Return an array with frame details
9897// args[0]: number: break id
9898// args[1]: number: frame index
9899//
9900// The array returned contains the following information:
9901// 0: Frame id
9902// 1: Receiver
9903// 2: Function
9904// 3: Argument count
9905// 4: Local count
9906// 5: Source position
9907// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009908// 7: Is at return
9909// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910// Arguments name, value
9911// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009912// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009913RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009914 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915 ASSERT(args.length() == 2);
9916
9917 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009918 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009919 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9920 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009921 if (!maybe_check->ToObject(&check)) return maybe_check;
9922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009924 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925
9926 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009927 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009928 if (id == StackFrame::NO_ID) {
9929 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009930 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009933 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934 for (; !it.done(); it.Advance()) {
9935 if (count == index) break;
9936 count++;
9937 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009940 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009941 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943 // Traverse the saved contexts chain to find the active context for the
9944 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009946 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009947 save = save->prev();
9948 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009949 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950
9951 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009953
9954 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009955 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009956 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957
9958 // Check for constructor frame.
9959 bool constructor = it.frame()->IsConstructor();
9960
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009961 // Get scope info and read from it for local variable information.
9962 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009963 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009964 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009966 // Get the nearest enclosing function context.
9967 Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009968
9969 // Get the locals names and values into a temporary array.
9970 //
9971 // TODO(1240907): Hide compiler-introduced stack variables
9972 // (e.g. .result)? For users of the debugger, they will probably be
9973 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009974 Handle<FixedArray> locals =
9975 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009977 // Fill in the names of the locals.
9978 for (int i = 0; i < info.NumberOfLocals(); i++) {
9979 locals->set(i * 2, *info.LocalName(i));
9980 }
9981
9982 // Fill in the values of the locals.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009983 if (is_optimized_frame) {
9984 // If we are inspecting an optimized frame use undefined as the
9985 // value for all locals.
9986 //
9987 // TODO(1140): We should be able to get the correct values
9988 // for locals in optimized frames.
9989 for (int i = 0; i < info.NumberOfLocals(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009991 }
9992 } else {
9993 for (int i = 0; i < info.number_of_stack_slots(); i++) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009994 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009996 }
9997 for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009998 Handle<String> name = info.LocalName(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010000 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010001 }
10002 }
10003
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010004 // Check whether this frame is positioned at return. If not top
10005 // frame or if the frame is optimized it cannot be at a return.
10006 bool at_return = false;
10007 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010009 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010010
10011 // If positioned just before return find the value to be returned and add it
10012 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010014 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010015 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010016 Address internal_frame_sp = NULL;
10017 while (!it2.done()) {
10018 if (it2.frame()->is_internal()) {
10019 internal_frame_sp = it2.frame()->sp();
10020 } else {
10021 if (it2.frame()->is_java_script()) {
10022 if (it2.frame()->id() == it.frame()->id()) {
10023 // The internal frame just before the JavaScript frame contains the
10024 // value to return on top. A debug break at return will create an
10025 // internal frame to store the return value (eax/rax/r0) before
10026 // entering the debug break exit frame.
10027 if (internal_frame_sp != NULL) {
10028 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 Handle<Object>(Memory::Object_at(internal_frame_sp),
10030 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010031 break;
10032 }
10033 }
10034 }
10035
10036 // Indicate that the previous frame was not an internal frame.
10037 internal_frame_sp = NULL;
10038 }
10039 it2.Advance();
10040 }
10041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042
10043 // Now advance to the arguments adapter frame (if any). It contains all
10044 // the provided parameters whereas the function frame always have the number
10045 // of arguments matching the functions parameters. The rest of the
10046 // information (except for what is collected above) is the same.
10047 it.AdvanceToArgumentsFrame();
10048
10049 // Find the number of arguments to fill. At least fill the number of
10050 // parameters for the function and fill more if more parameters are provided.
10051 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010052 if (argument_count < it.frame()->ComputeParametersCount()) {
10053 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054 }
10055
10056 // Calculate the size of the result.
10057 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010058 2 * (argument_count + info.NumberOfLocals()) +
10059 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010060 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010061
10062 // Add the frame id.
10063 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10064
10065 // Add the function (same as in function frame).
10066 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
10067
10068 // Add the arguments count.
10069 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10070
10071 // Add the locals count
10072 details->set(kFrameDetailsLocalCountIndex,
10073 Smi::FromInt(info.NumberOfLocals()));
10074
10075 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010076 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10078 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010079 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010080 }
10081
10082 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010085 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010086 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010087
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010088 // Add information on whether this frame is invoked in the debugger context.
10089 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 heap->ToBoolean(*save->context() ==
10091 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092
10093 // Fill the dynamic part.
10094 int details_index = kFrameDetailsFirstDynamicIndex;
10095
10096 // Add arguments name and value.
10097 for (int i = 0; i < argument_count; i++) {
10098 // Name of the argument.
10099 if (i < info.number_of_parameters()) {
10100 details->set(details_index++, *info.parameter_name(i));
10101 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 }
10104
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010105 // Parameter value. If we are inspecting an optimized frame, use
10106 // undefined as the value.
10107 //
10108 // TODO(3141533): We should be able to get the actual parameter
10109 // value for optimized frames.
10110 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010111 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112 details->set(details_index++, it.frame()->GetParameter(i));
10113 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 }
10116 }
10117
10118 // Add locals name and value from the temporary copy from the function frame.
10119 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10120 details->set(details_index++, locals->get(i));
10121 }
10122
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010123 // Add the value being returned.
10124 if (at_return) {
10125 details->set(details_index++, *return_value);
10126 }
10127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010128 // Add the receiver (same as in function frame).
10129 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10130 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010131 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010132 if (!receiver->IsJSObject()) {
10133 // If the receiver is NOT a JSObject we have hit an optimization
10134 // where a value object is not converted into a wrapped JS objects.
10135 // To hide this optimization from the debugger, we wrap the receiver
10136 // by creating correct wrapper object based on the calling frame's
10137 // global context.
10138 it.Advance();
10139 Handle<Context> calling_frames_global_context(
10140 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010141 receiver =
10142 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143 }
10144 details->set(kFrameDetailsReceiverIndex, *receiver);
10145
10146 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010147 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148}
10149
10150
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010151// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010152static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010153 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010154 Handle<SerializedScopeInfo> serialized_scope_info,
10155 ScopeInfo<>& scope_info,
10156 Handle<Context> context,
10157 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010158 // Fill all context locals to the context extension.
10159 for (int i = Context::MIN_CONTEXT_SLOTS;
10160 i < scope_info.number_of_context_slots();
10161 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010162 int context_index = serialized_scope_info->ContextSlotIndex(
10163 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010164
whesse@chromium.org7b260152011-06-20 15:33:18 +000010165 RETURN_IF_EMPTY_HANDLE_VALUE(
10166 isolate,
10167 SetProperty(scope_object,
10168 scope_info.context_slot_name(i),
10169 Handle<Object>(context->get(context_index), isolate),
10170 NONE,
10171 kNonStrictMode),
10172 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010173 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010174
10175 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010176}
10177
10178
10179// Create a plain JSObject which materializes the local scope for the specified
10180// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010181static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10182 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010183 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010184 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010185 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10186 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010187
10188 // Allocate and initialize a JSObject with all the arguments, stack locals
10189 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190 Handle<JSObject> local_scope =
10191 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010192
10193 // First fill all parameters.
10194 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010195 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010197 SetProperty(local_scope,
10198 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010200 NONE,
10201 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010202 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010203 }
10204
10205 // Second fill all stack locals.
10206 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010207 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010208 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010209 SetProperty(local_scope,
10210 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010211 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010212 NONE,
10213 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010214 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010215 }
10216
10217 // Third fill all context locals.
10218 Handle<Context> frame_context(Context::cast(frame->context()));
10219 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 if (!CopyContextLocalsToScopeObject(isolate,
10221 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010222 function_context, local_scope)) {
10223 return Handle<JSObject>();
10224 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010225
10226 // Finally copy any properties from the function context extension. This will
10227 // be variables introduced by eval.
10228 if (function_context->closure() == *function) {
10229 if (function_context->has_extension() &&
10230 !function_context->IsGlobalContext()) {
10231 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010232 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010233 for (int i = 0; i < keys->length(); i++) {
10234 // Names of variables introduced by eval are strings.
10235 ASSERT(keys->get(i)->IsString());
10236 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010237 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010238 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010239 SetProperty(local_scope,
10240 key,
10241 GetProperty(ext, key),
10242 NONE,
10243 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010244 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010245 }
10246 }
10247 }
10248 return local_scope;
10249}
10250
10251
10252// Create a plain JSObject which materializes the closure content for the
10253// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10255 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010256 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010257
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010258 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010259 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10260 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010261
10262 // Allocate and initialize a JSObject with all the content of theis function
10263 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010264 Handle<JSObject> closure_scope =
10265 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010266
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010267 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 if (!CopyContextLocalsToScopeObject(isolate,
10269 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010270 context, closure_scope)) {
10271 return Handle<JSObject>();
10272 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010273
10274 // Finally copy any properties from the function context extension. This will
10275 // be variables introduced by eval.
10276 if (context->has_extension()) {
10277 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010278 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010279 for (int i = 0; i < keys->length(); i++) {
10280 // Names of variables introduced by eval are strings.
10281 ASSERT(keys->get(i)->IsString());
10282 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 RETURN_IF_EMPTY_HANDLE_VALUE(
10284 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010285 SetProperty(closure_scope,
10286 key,
10287 GetProperty(ext, key),
10288 NONE,
10289 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010290 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010291 }
10292 }
10293
10294 return closure_scope;
10295}
10296
10297
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010298// Create a plain JSObject which materializes the scope for the specified
10299// catch context.
10300static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10301 Handle<Context> context) {
10302 ASSERT(context->IsCatchContext());
10303 Handle<String> name(String::cast(context->extension()));
10304 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10305 Handle<JSObject> catch_scope =
10306 isolate->factory()->NewJSObject(isolate->object_function());
10307 RETURN_IF_EMPTY_HANDLE_VALUE(
10308 isolate,
10309 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10310 Handle<JSObject>());
10311 return catch_scope;
10312}
10313
10314
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010315// Iterate over the actual scopes visible from a stack frame. All scopes are
10316// backed by an actual context except the local scope, which is inserted
10317// "artifically" in the context chain.
10318class ScopeIterator {
10319 public:
10320 enum ScopeType {
10321 ScopeTypeGlobal = 0,
10322 ScopeTypeLocal,
10323 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010324 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010325 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010326 };
10327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010328 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10329 : isolate_(isolate),
10330 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010331 function_(JSFunction::cast(frame->function())),
10332 context_(Context::cast(frame->context())),
10333 local_done_(false),
10334 at_local_(false) {
10335
10336 // Check whether the first scope is actually a local scope.
10337 if (context_->IsGlobalContext()) {
10338 // If there is a stack slot for .result then this local scope has been
10339 // created for evaluating top level code and it is not a real local scope.
10340 // Checking for the existence of .result seems fragile, but the scope info
10341 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010342 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010343 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010344 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010345 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010346 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010347 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010348 // The context_ is a with or catch block from the outer function.
10349 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010350 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010351 }
10352 }
10353
10354 // More scopes?
10355 bool Done() { return context_.is_null(); }
10356
10357 // Move to the next scope.
10358 void Next() {
10359 // If at a local scope mark the local scope as passed.
10360 if (at_local_) {
10361 at_local_ = false;
10362 local_done_ = true;
10363
10364 // If the current context is not associated with the local scope the
10365 // current context is the next real scope, so don't move to the next
10366 // context in this case.
10367 if (context_->closure() != *function_) {
10368 return;
10369 }
10370 }
10371
10372 // The global scope is always the last in the chain.
10373 if (context_->IsGlobalContext()) {
10374 context_ = Handle<Context>();
10375 return;
10376 }
10377
10378 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010379 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010380
10381 // If passing the local scope indicate that the current scope is now the
10382 // local scope.
10383 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010384 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010385 at_local_ = true;
10386 }
10387 }
10388
10389 // Return the type of the current scope.
10390 int Type() {
10391 if (at_local_) {
10392 return ScopeTypeLocal;
10393 }
10394 if (context_->IsGlobalContext()) {
10395 ASSERT(context_->global()->IsGlobalObject());
10396 return ScopeTypeGlobal;
10397 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010398 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010399 return ScopeTypeClosure;
10400 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010401 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010402 return ScopeTypeCatch;
10403 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010404 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010405 return ScopeTypeWith;
10406 }
10407
10408 // Return the JavaScript object with the content of the current scope.
10409 Handle<JSObject> ScopeObject() {
10410 switch (Type()) {
10411 case ScopeIterator::ScopeTypeGlobal:
10412 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010413 case ScopeIterator::ScopeTypeLocal:
10414 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010415 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010416 case ScopeIterator::ScopeTypeWith:
10417 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010418 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10419 case ScopeIterator::ScopeTypeCatch:
10420 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010421 case ScopeIterator::ScopeTypeClosure:
10422 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010423 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010424 }
10425 UNREACHABLE();
10426 return Handle<JSObject>();
10427 }
10428
10429 // Return the context for this scope. For the local context there might not
10430 // be an actual context.
10431 Handle<Context> CurrentContext() {
10432 if (at_local_ && context_->closure() != *function_) {
10433 return Handle<Context>();
10434 }
10435 return context_;
10436 }
10437
10438#ifdef DEBUG
10439 // Debug print of the content of the current scope.
10440 void DebugPrint() {
10441 switch (Type()) {
10442 case ScopeIterator::ScopeTypeGlobal:
10443 PrintF("Global:\n");
10444 CurrentContext()->Print();
10445 break;
10446
10447 case ScopeIterator::ScopeTypeLocal: {
10448 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010449 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010450 scope_info.Print();
10451 if (!CurrentContext().is_null()) {
10452 CurrentContext()->Print();
10453 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010454 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010455 if (extension->IsJSContextExtensionObject()) {
10456 extension->Print();
10457 }
10458 }
10459 }
10460 break;
10461 }
10462
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010463 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010464 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010465 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010466 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010468 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010469 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010470 CurrentContext()->extension()->Print();
10471 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010472 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010473
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010474 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010475 PrintF("Closure:\n");
10476 CurrentContext()->Print();
10477 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010478 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010479 if (extension->IsJSContextExtensionObject()) {
10480 extension->Print();
10481 }
10482 }
10483 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010484
10485 default:
10486 UNREACHABLE();
10487 }
10488 PrintF("\n");
10489 }
10490#endif
10491
10492 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010494 JavaScriptFrame* frame_;
10495 Handle<JSFunction> function_;
10496 Handle<Context> context_;
10497 bool local_done_;
10498 bool at_local_;
10499
10500 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10501};
10502
10503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010504RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010505 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010506 ASSERT(args.length() == 2);
10507
10508 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010509 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010510 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10511 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010512 if (!maybe_check->ToObject(&check)) return maybe_check;
10513 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010514 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10515
10516 // Get the frame where the debugging is performed.
10517 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010518 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010519 JavaScriptFrame* frame = it.frame();
10520
10521 // Count the visible scopes.
10522 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010524 n++;
10525 }
10526
10527 return Smi::FromInt(n);
10528}
10529
10530
10531static const int kScopeDetailsTypeIndex = 0;
10532static const int kScopeDetailsObjectIndex = 1;
10533static const int kScopeDetailsSize = 2;
10534
10535// Return an array with scope details
10536// args[0]: number: break id
10537// args[1]: number: frame index
10538// args[2]: number: scope index
10539//
10540// The array returned contains the following information:
10541// 0: Scope type
10542// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010543RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010545 ASSERT(args.length() == 3);
10546
10547 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010548 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010549 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10550 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010551 if (!maybe_check->ToObject(&check)) return maybe_check;
10552 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010553 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10554 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10555
10556 // Get the frame where the debugging is performed.
10557 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010558 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010559 JavaScriptFrame* frame = frame_it.frame();
10560
10561 // Find the requested scope.
10562 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010563 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010564 for (; !it.Done() && n < index; it.Next()) {
10565 n++;
10566 }
10567 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010568 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010569 }
10570
10571 // Calculate the size of the result.
10572 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010574
10575 // Fill in scope details.
10576 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010577 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010579 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010582}
10583
10584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010585RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010587 ASSERT(args.length() == 0);
10588
10589#ifdef DEBUG
10590 // Print the scopes for the top frame.
10591 StackFrameLocator locator;
10592 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010594 it.DebugPrint();
10595 }
10596#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010598}
10599
10600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010603 ASSERT(args.length() == 1);
10604
10605 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010606 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010607 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10608 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010609 if (!maybe_result->ToObject(&result)) return maybe_result;
10610 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010611
10612 // Count all archived V8 threads.
10613 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 for (ThreadState* thread =
10615 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010616 thread != NULL;
10617 thread = thread->Next()) {
10618 n++;
10619 }
10620
10621 // Total number of threads is current thread and archived threads.
10622 return Smi::FromInt(n + 1);
10623}
10624
10625
10626static const int kThreadDetailsCurrentThreadIndex = 0;
10627static const int kThreadDetailsThreadIdIndex = 1;
10628static const int kThreadDetailsSize = 2;
10629
10630// Return an array with thread details
10631// args[0]: number: break id
10632// args[1]: number: thread index
10633//
10634// The array returned contains the following information:
10635// 0: Is current thread?
10636// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010637RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010639 ASSERT(args.length() == 2);
10640
10641 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010642 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010643 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10644 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010645 if (!maybe_check->ToObject(&check)) return maybe_check;
10646 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010647 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10648
10649 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010650 Handle<FixedArray> details =
10651 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010652
10653 // Thread index 0 is current thread.
10654 if (index == 0) {
10655 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 details->set(kThreadDetailsCurrentThreadIndex,
10657 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010658 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010659 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010660 } else {
10661 // Find the thread with the requested index.
10662 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010663 ThreadState* thread =
10664 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010665 while (index != n && thread != NULL) {
10666 thread = thread->Next();
10667 n++;
10668 }
10669 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010671 }
10672
10673 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010674 details->set(kThreadDetailsCurrentThreadIndex,
10675 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010676 details->set(kThreadDetailsThreadIdIndex,
10677 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010678 }
10679
10680 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010682}
10683
10684
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010685// Sets the disable break state
10686// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010687RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010688 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010689 ASSERT(args.length() == 1);
10690 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010691 isolate->debug()->set_disable_break(disable_break);
10692 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010693}
10694
10695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010696RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 ASSERT(args.length() == 1);
10699
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010700 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10701 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702 // Find the number of break points
10703 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010704 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010705 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010706 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 Handle<FixedArray>::cast(break_locations));
10708}
10709
10710
10711// Set a break point in a function
10712// args[0]: function
10713// args[1]: number: break source position (within the function source)
10714// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010715RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010718 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10719 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10721 RUNTIME_ASSERT(source_position >= 0);
10722 Handle<Object> break_point_object_arg = args.at<Object>(2);
10723
10724 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010725 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10726 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010728 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729}
10730
10731
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010732Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10733 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010734 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 // Iterate the heap looking for SharedFunctionInfo generated from the
10736 // script. The inner most SharedFunctionInfo containing the source position
10737 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010738 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010739 // which is found is not compiled it is compiled and the heap is iterated
10740 // again as the compilation might create inner functions from the newly
10741 // compiled function and the actual requested break point might be in one of
10742 // these functions.
10743 bool done = false;
10744 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010745 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747 while (!done) {
10748 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010749 for (HeapObject* obj = iterator.next();
10750 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 if (obj->IsSharedFunctionInfo()) {
10752 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10753 if (shared->script() == *script) {
10754 // If the SharedFunctionInfo found has the requested script data and
10755 // contains the source position it is a candidate.
10756 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010757 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 start_position = shared->start_position();
10759 }
10760 if (start_position <= position &&
10761 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010762 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763 // candidate this is the new candidate.
10764 if (target.is_null()) {
10765 target_start_position = start_position;
10766 target = shared;
10767 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010768 if (target_start_position == start_position &&
10769 shared->end_position() == target->end_position()) {
10770 // If a top-level function contain only one function
10771 // declartion the source for the top-level and the function is
10772 // the same. In that case prefer the non top-level function.
10773 if (!shared->is_toplevel()) {
10774 target_start_position = start_position;
10775 target = shared;
10776 }
10777 } else if (target_start_position <= start_position &&
10778 shared->end_position() <= target->end_position()) {
10779 // This containment check includes equality as a function inside
10780 // a top-level function can share either start or end position
10781 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782 target_start_position = start_position;
10783 target = shared;
10784 }
10785 }
10786 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787 }
10788 }
10789 }
10790
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010793 }
10794
10795 // If the candidate found is compiled we are done. NOTE: when lazy
10796 // compilation of inner functions is introduced some additional checking
10797 // needs to be done here to compile inner functions.
10798 done = target->is_compiled();
10799 if (!done) {
10800 // If the candidate is not compiled compile it to reveal any inner
10801 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010802 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010803 }
10804 }
10805
10806 return *target;
10807}
10808
10809
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010810// Changes the state of a break point in a script and returns source position
10811// where break point was set. NOTE: Regarding performance see the NOTE for
10812// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010813// args[0]: script to set break point in
10814// args[1]: number: break source position (within the script source)
10815// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010816RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 ASSERT(args.length() == 3);
10819 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10820 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10821 RUNTIME_ASSERT(source_position >= 0);
10822 Handle<Object> break_point_object_arg = args.at<Object>(2);
10823
10824 // Get the script from the script wrapper.
10825 RUNTIME_ASSERT(wrapper->value()->IsScript());
10826 Handle<Script> script(Script::cast(wrapper->value()));
10827
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010828 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010829 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830 if (!result->IsUndefined()) {
10831 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10832 // Find position within function. The script position might be before the
10833 // source position of the first function.
10834 int position;
10835 if (shared->start_position() > source_position) {
10836 position = 0;
10837 } else {
10838 position = source_position - shared->start_position();
10839 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010841 position += shared->start_position();
10842 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010844 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010845}
10846
10847
10848// Clear a break point
10849// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010850RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010851 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010852 ASSERT(args.length() == 1);
10853 Handle<Object> break_point_object_arg = args.at<Object>(0);
10854
10855 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010856 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859}
10860
10861
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010862// Change the state of break on exceptions.
10863// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10864// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010865RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010866 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010868 RUNTIME_ASSERT(args[0]->IsNumber());
10869 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010870
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010871 // If the number doesn't match an enum value, the ChangeBreakOnException
10872 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 ExceptionBreakType type =
10874 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010875 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 isolate->debug()->ChangeBreakOnException(type, enable);
10877 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878}
10879
10880
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010881// Returns the state of break on exceptions
10882// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010883RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010885 ASSERT(args.length() == 1);
10886 RUNTIME_ASSERT(args[0]->IsNumber());
10887
10888 ExceptionBreakType type =
10889 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010890 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010891 return Smi::FromInt(result);
10892}
10893
10894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895// Prepare for stepping
10896// args[0]: break id for checking execution state
10897// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010898// args[2]: number of times to perform the step, for step out it is the number
10899// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010900RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010901 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902 ASSERT(args.length() == 3);
10903 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010904 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010905 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10906 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010907 if (!maybe_check->ToObject(&check)) return maybe_check;
10908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010910 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010911 }
10912
10913 // Get the step action and check validity.
10914 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10915 if (step_action != StepIn &&
10916 step_action != StepNext &&
10917 step_action != StepOut &&
10918 step_action != StepInMin &&
10919 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010920 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010921 }
10922
10923 // Get the number of steps.
10924 int step_count = NumberToInt32(args[2]);
10925 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927 }
10928
ager@chromium.orga1645e22009-09-09 19:27:10 +000010929 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010930 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010933 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10934 step_count);
10935 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936}
10937
10938
10939// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010940RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010941 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010942 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010943 isolate->debug()->ClearStepping();
10944 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945}
10946
10947
10948// Creates a copy of the with context chain. The copy of the context chain is
10949// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010950static Handle<Context> CopyWithContextChain(Isolate* isolate,
10951 Handle<Context> current,
10952 Handle<Context> base) {
10953 // At the end of the chain. Return the base context to link to.
10954 if (current->IsFunctionContext() || current->IsGlobalContext()) {
10955 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956 }
10957
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010958 // Recursively copy the with and catch contexts.
10959 HandleScope scope(isolate);
10960 Handle<Context> previous(current->previous());
10961 Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
10962 Handle<Context> new_current;
10963 if (current->IsCatchContext()) {
10964 Handle<String> name(String::cast(current->extension()));
10965 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
10966 new_current =
10967 isolate->factory()->NewCatchContext(new_previous, name, thrown_object);
10968 } else {
10969 Handle<JSObject> extension(JSObject::cast(current->extension()));
10970 new_current =
10971 isolate->factory()->NewWithContext(new_previous, extension);
10972 }
10973 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974}
10975
10976
10977// Helper function to find or create the arguments object for
10978// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010979static Handle<Object> GetArgumentsObject(Isolate* isolate,
10980 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010982 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983 const ScopeInfo<>* sinfo,
10984 Handle<Context> function_context) {
10985 // Try to find the value of 'arguments' to pass as parameter. If it is not
10986 // found (that is the debugged function does not reference 'arguments' and
10987 // does not support eval) then create an 'arguments' object.
10988 int index;
10989 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010992 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993 }
10994 }
10995
10996 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10998 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010999 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011000 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 }
11002 }
11003
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011004 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011005 Handle<JSObject> arguments =
11006 isolate->factory()->NewArgumentsObject(function, length);
11007 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011008
11009 AssertNoAllocation no_gc;
11010 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011012 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011013 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011014 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011015 return arguments;
11016}
11017
11018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011019static const char kSourceStr[] =
11020 "(function(arguments,__source__){return eval(__source__);})";
11021
11022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011023// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011024// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011025// extension part has all the parameters and locals of the function on the
11026// stack frame. A function which calls eval with the code to evaluate is then
11027// compiled in this context and called in this context. As this context
11028// replaces the context of the function on the stack frame a new (empty)
11029// function is created as well to be used as the closure for the context.
11030// This function and the context acts as replacements for the function on the
11031// stack frame presenting the same view of the values of parameters and
11032// local variables as if the piece of JavaScript was evaluated at the point
11033// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011034RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011035 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011036
11037 // Check the execution state and decode arguments frame and source to be
11038 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011039 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011040 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011041 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11042 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011043 if (!maybe_check_result->ToObject(&check_result)) {
11044 return maybe_check_result;
11045 }
11046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011047 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11048 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011049 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011050 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011051
11052 // Handle the processing of break.
11053 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054
11055 // Get the frame where the debugging is performed.
11056 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011057 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058 JavaScriptFrame* frame = it.frame();
11059 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011060 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011061 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011062
11063 // Traverse the saved contexts chain to find the active context for the
11064 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011065 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011066 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011067 save = save->prev();
11068 }
11069 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011070 SaveContext savex(isolate);
11071 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011072
11073 // Create the (empty) function replacing the function on the stack frame for
11074 // the purpose of evaluating in the context created below. It is important
11075 // that this function does not describe any parameters and local variables
11076 // in the context. If it does then this will cause problems with the lookup
11077 // in Context::Lookup, where context slots for parameters and local variables
11078 // are looked at before the extension object.
11079 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11081 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011082 go_between->set_context(function->context());
11083#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011084 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11086 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11087#endif
11088
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011089 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011090 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
11091 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011092
11093 // Allocate a new context for the debug evaluation and set the extension
11094 // object build.
11095 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011096 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11097 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011099 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100 Handle<Context> frame_context(Context::cast(frame->context()));
11101 Handle<Context> function_context(frame_context->fcontext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011102 context = CopyWithContextChain(isolate, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011103
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011104 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011105 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
11106 context = isolate->factory()->NewWithContext(context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011107 }
11108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011109 // Wrap the evaluation statement in a new function compiled in the newly
11110 // created context. The function has one parameter which has to be called
11111 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011112 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011113 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011114
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 isolate->factory()->NewStringFromAscii(
11117 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011118
11119 // Currently, the eval code will be executed in non-strict mode,
11120 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011121 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011122 Compiler::CompileEval(function_source,
11123 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011124 context->IsGlobalContext(),
11125 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011126 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129
11130 // Invoke the result of the compilation to get the evaluation function.
11131 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011132 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133 Handle<Object> evaluation_function =
11134 Execution::Call(compiled_function, receiver, 0, NULL,
11135 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011136 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011138 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11139 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011140 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141
11142 // Invoke the evaluation function and return the result.
11143 const int argc = 2;
11144 Object** argv[argc] = { arguments.location(),
11145 Handle<Object>::cast(source).location() };
11146 Handle<Object> result =
11147 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11148 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011149 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011150
11151 // Skip the global proxy as it has no properties and always delegates to the
11152 // real global object.
11153 if (result->IsJSGlobalProxy()) {
11154 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11155 }
11156
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011157 return *result;
11158}
11159
11160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011161RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011162 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011163
11164 // Check the execution state and decode arguments frame and source to be
11165 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011166 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011167 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011168 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11169 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011170 if (!maybe_check_result->ToObject(&check_result)) {
11171 return maybe_check_result;
11172 }
11173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011174 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011175 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011176 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011177
11178 // Handle the processing of break.
11179 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180
11181 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011182 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011183 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011184 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185 top = top->prev();
11186 }
11187 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011188 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011189 }
11190
11191 // Get the global context now set to the top context from before the
11192 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011193 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011195 bool is_global = true;
11196
11197 if (additional_context->IsJSObject()) {
11198 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011199 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11200 isolate->factory()->empty_string(),
11201 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011202 go_between->set_context(*context);
11203 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011204 isolate->factory()->NewFunctionContext(
11205 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011206 context->set_extension(JSObject::cast(*additional_context));
11207 is_global = false;
11208 }
11209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011210 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011211 // Currently, the eval code will be executed in non-strict mode,
11212 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011213 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011214 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011215 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011217 Handle<JSFunction>(
11218 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11219 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011220
11221 // Invoke the result of the compilation to get the evaluation function.
11222 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011223 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011224 Handle<Object> result =
11225 Execution::Call(compiled_function, receiver, 0, NULL,
11226 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011227 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011228 return *result;
11229}
11230
11231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011232RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011233 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011234 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011235
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011236 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011237 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011238
11239 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011240 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011241 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11242 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11243 // because using
11244 // instances->set(i, *GetScriptWrapper(script))
11245 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11246 // already have deferenced the instances handle.
11247 Handle<JSValue> wrapper = GetScriptWrapper(script);
11248 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011249 }
11250
11251 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011252 Handle<JSObject> result =
11253 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011254 Handle<JSArray>::cast(result)->SetContent(*instances);
11255 return *result;
11256}
11257
11258
11259// Helper function used by Runtime_DebugReferencedBy below.
11260static int DebugReferencedBy(JSObject* target,
11261 Object* instance_filter, int max_references,
11262 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011263 JSFunction* arguments_function) {
11264 NoHandleAllocation ha;
11265 AssertNoAllocation no_alloc;
11266
11267 // Iterate the heap.
11268 int count = 0;
11269 JSObject* last = NULL;
11270 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011271 HeapObject* heap_obj = NULL;
11272 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273 (max_references == 0 || count < max_references)) {
11274 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011275 if (heap_obj->IsJSObject()) {
11276 // Skip context extension objects and argument arrays as these are
11277 // checked in the context of functions using them.
11278 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011279 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011280 obj->map()->constructor() == arguments_function) {
11281 continue;
11282 }
11283
11284 // Check if the JS object has a reference to the object looked for.
11285 if (obj->ReferencesObject(target)) {
11286 // Check instance filter if supplied. This is normally used to avoid
11287 // references from mirror objects (see Runtime_IsInPrototypeChain).
11288 if (!instance_filter->IsUndefined()) {
11289 Object* V = obj;
11290 while (true) {
11291 Object* prototype = V->GetPrototype();
11292 if (prototype->IsNull()) {
11293 break;
11294 }
11295 if (instance_filter == prototype) {
11296 obj = NULL; // Don't add this object.
11297 break;
11298 }
11299 V = prototype;
11300 }
11301 }
11302
11303 if (obj != NULL) {
11304 // Valid reference found add to instance array if supplied an update
11305 // count.
11306 if (instances != NULL && count < instances_size) {
11307 instances->set(count, obj);
11308 }
11309 last = obj;
11310 count++;
11311 }
11312 }
11313 }
11314 }
11315
11316 // Check for circular reference only. This can happen when the object is only
11317 // referenced from mirrors and has a circular reference in which case the
11318 // object is not really alive and would have been garbage collected if not
11319 // referenced from the mirror.
11320 if (count == 1 && last == target) {
11321 count = 0;
11322 }
11323
11324 // Return the number of referencing objects found.
11325 return count;
11326}
11327
11328
11329// Scan the heap for objects with direct references to an object
11330// args[0]: the object to find references to
11331// args[1]: constructor function for instances to exclude (Mirror)
11332// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011333RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011334 ASSERT(args.length() == 3);
11335
11336 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338
11339 // Check parameters.
11340 CONVERT_CHECKED(JSObject, target, args[0]);
11341 Object* instance_filter = args[1];
11342 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11343 instance_filter->IsJSObject());
11344 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11345 RUNTIME_ASSERT(max_references >= 0);
11346
11347 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011348 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011350 JSFunction* arguments_function =
11351 JSFunction::cast(arguments_boilerplate->map()->constructor());
11352
11353 // Get the number of referencing objects.
11354 int count;
11355 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011356 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357
11358 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011359 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011361 if (!maybe_object->ToObject(&object)) return maybe_object;
11362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011363 FixedArray* instances = FixedArray::cast(object);
11364
11365 // Fill the referencing objects.
11366 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011367 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368
11369 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011370 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11372 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011373 if (!maybe_result->ToObject(&result)) return maybe_result;
11374 }
11375 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011376 return result;
11377}
11378
11379
11380// Helper function used by Runtime_DebugConstructedBy below.
11381static int DebugConstructedBy(JSFunction* constructor, int max_references,
11382 FixedArray* instances, int instances_size) {
11383 AssertNoAllocation no_alloc;
11384
11385 // Iterate the heap.
11386 int count = 0;
11387 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011388 HeapObject* heap_obj = NULL;
11389 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011390 (max_references == 0 || count < max_references)) {
11391 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011392 if (heap_obj->IsJSObject()) {
11393 JSObject* obj = JSObject::cast(heap_obj);
11394 if (obj->map()->constructor() == constructor) {
11395 // Valid reference found add to instance array if supplied an update
11396 // count.
11397 if (instances != NULL && count < instances_size) {
11398 instances->set(count, obj);
11399 }
11400 count++;
11401 }
11402 }
11403 }
11404
11405 // Return the number of referencing objects found.
11406 return count;
11407}
11408
11409
11410// Scan the heap for objects constructed by a specific function.
11411// args[0]: the constructor to find instances of
11412// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011413RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011414 ASSERT(args.length() == 2);
11415
11416 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418
11419 // Check parameters.
11420 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11421 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11422 RUNTIME_ASSERT(max_references >= 0);
11423
11424 // Get the number of referencing objects.
11425 int count;
11426 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11427
11428 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011429 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011430 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011431 if (!maybe_object->ToObject(&object)) return maybe_object;
11432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011433 FixedArray* instances = FixedArray::cast(object);
11434
11435 // Fill the referencing objects.
11436 count = DebugConstructedBy(constructor, max_references, instances, count);
11437
11438 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011439 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11441 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011442 if (!maybe_result->ToObject(&result)) return maybe_result;
11443 }
11444 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011445 return result;
11446}
11447
11448
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011449// Find the effective prototype object as returned by __proto__.
11450// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011451RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011452 ASSERT(args.length() == 1);
11453
11454 CONVERT_CHECKED(JSObject, obj, args[0]);
11455
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011456 // Use the __proto__ accessor.
11457 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011458}
11459
11460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011461RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011462 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011463 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011465}
11466
11467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011468RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011469#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011470 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011471 ASSERT(args.length() == 1);
11472 // Get the function and make sure it is compiled.
11473 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011474 Handle<SharedFunctionInfo> shared(func->shared());
11475 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011476 return Failure::Exception();
11477 }
11478 func->code()->PrintLn();
11479#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011481}
ager@chromium.org9085a012009-05-11 19:22:57 +000011482
11483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011484RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011485#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011486 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011487 ASSERT(args.length() == 1);
11488 // Get the function and make sure it is compiled.
11489 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011490 Handle<SharedFunctionInfo> shared(func->shared());
11491 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011492 return Failure::Exception();
11493 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011494 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011495#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011496 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011497}
11498
11499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011500RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011501 NoHandleAllocation ha;
11502 ASSERT(args.length() == 1);
11503
11504 CONVERT_CHECKED(JSFunction, f, args[0]);
11505 return f->shared()->inferred_name();
11506}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011507
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011508
11509static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011510 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011511 AssertNoAllocation no_allocations;
11512
11513 int counter = 0;
11514 int buffer_size = buffer->length();
11515 HeapIterator iterator;
11516 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11517 ASSERT(obj != NULL);
11518 if (!obj->IsSharedFunctionInfo()) {
11519 continue;
11520 }
11521 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11522 if (shared->script() != script) {
11523 continue;
11524 }
11525 if (counter < buffer_size) {
11526 buffer->set(counter, shared);
11527 }
11528 counter++;
11529 }
11530 return counter;
11531}
11532
11533// For a script finds all SharedFunctionInfo's in the heap that points
11534// to this script. Returns JSArray of SharedFunctionInfo wrapped
11535// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536RUNTIME_FUNCTION(MaybeObject*,
11537 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011538 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011539 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011540 CONVERT_CHECKED(JSValue, script_value, args[0]);
11541
11542 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11543
11544 const int kBufferSize = 32;
11545
11546 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011548 int number = FindSharedFunctionInfosForScript(*script, *array);
11549 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011551 FindSharedFunctionInfosForScript(*script, *array);
11552 }
11553
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011555 result->set_length(Smi::FromInt(number));
11556
11557 LiveEdit::WrapSharedFunctionInfos(result);
11558
11559 return *result;
11560}
11561
11562// For a script calculates compilation information about all its functions.
11563// The script source is explicitly specified by the second argument.
11564// The source of the actual script is not used, however it is important that
11565// all generated code keeps references to this particular instance of script.
11566// Returns a JSArray of compilation infos. The array is ordered so that
11567// each function with all its descendant is always stored in a continues range
11568// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011569RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011570 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011572 CONVERT_CHECKED(JSValue, script, args[0]);
11573 CONVERT_ARG_CHECKED(String, source, 1);
11574 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11575
11576 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11577
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011579 return Failure::Exception();
11580 }
11581
11582 return result;
11583}
11584
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011585// Changes the source of the script to a new_source.
11586// If old_script_name is provided (i.e. is a String), also creates a copy of
11587// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011588RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011589 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011591 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11592 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011594
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011595 CONVERT_CHECKED(Script, original_script_pointer,
11596 original_script_value->value());
11597 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011598
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011599 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11600 new_source,
11601 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011602
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011603 if (old_script->IsScript()) {
11604 Handle<Script> script_handle(Script::cast(old_script));
11605 return *(GetScriptWrapper(script_handle));
11606 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011607 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011608 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011609}
11610
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011612RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011613 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011615 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11616 return LiveEdit::FunctionSourceUpdated(shared_info);
11617}
11618
11619
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011620// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011621RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011622 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011624 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11625 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11626
ager@chromium.orgac091b72010-05-05 07:34:42 +000011627 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011628}
11629
11630// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011631RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011632 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 HandleScope scope(isolate);
11634 Handle<Object> function_object(args[0], isolate);
11635 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011636
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011637 if (function_object->IsJSValue()) {
11638 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11639 if (script_object->IsJSValue()) {
11640 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011641 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011642 }
11643
11644 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11645 } else {
11646 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11647 // and we check it in this function.
11648 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011651}
11652
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011653
11654// In a code of a parent function replaces original function as embedded object
11655// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011656RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011657 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011659
11660 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11661 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11662 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11663
11664 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11665 subst_wrapper);
11666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011668}
11669
11670
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011671// Updates positions of a shared function info (first parameter) according
11672// to script source change. Text change is described in second parameter as
11673// array of groups of 3 numbers:
11674// (change_begin, change_end, change_end_new_position).
11675// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011676RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011677 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011679 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11680 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11681
ager@chromium.orgac091b72010-05-05 07:34:42 +000011682 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011683}
11684
11685
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011686// For array of SharedFunctionInfo's (each wrapped in JSValue)
11687// checks that none of them have activations on stacks (of any thread).
11688// Returns array of the same length with corresponding results of
11689// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011690RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011691 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011693 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011694 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011695
ager@chromium.org357bf652010-04-12 11:30:10 +000011696 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011697}
11698
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011699// Compares 2 strings line-by-line, then token-wise and returns diff in form
11700// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11701// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011702RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011703 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011704 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011705 CONVERT_ARG_CHECKED(String, s1, 0);
11706 CONVERT_ARG_CHECKED(String, s2, 1);
11707
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011708 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011709}
11710
11711
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011712// A testing entry. Returns statement position which is the closest to
11713// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011715 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011717 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11718 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011721
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011722 if (code->kind() != Code::FUNCTION &&
11723 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011725 }
11726
11727 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011728 int closest_pc = 0;
11729 int distance = kMaxInt;
11730 while (!it.done()) {
11731 int statement_position = static_cast<int>(it.rinfo()->data());
11732 // Check if this break point is closer that what was previously found.
11733 if (source_position <= statement_position &&
11734 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011735 closest_pc =
11736 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011737 distance = statement_position - source_position;
11738 // Check whether we can't get any closer.
11739 if (distance == 0) break;
11740 }
11741 it.next();
11742 }
11743
11744 return Smi::FromInt(closest_pc);
11745}
11746
11747
ager@chromium.org357bf652010-04-12 11:30:10 +000011748// Calls specified function with or without entering the debugger.
11749// This is used in unit tests to run code as if debugger is entered or simply
11750// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011751RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011752 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011754 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11755 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11756
11757 Handle<Object> result;
11758 bool pending_exception;
11759 {
11760 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011762 &pending_exception);
11763 } else {
11764 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011765 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011766 &pending_exception);
11767 }
11768 }
11769 if (!pending_exception) {
11770 return *result;
11771 } else {
11772 return Failure::Exception();
11773 }
11774}
11775
11776
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011777// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011778RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011779 CONVERT_CHECKED(String, arg, args[0]);
11780 SmartPointer<char> flags =
11781 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11782 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011783 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011784}
11785
11786
11787// Performs a GC.
11788// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011789RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 isolate->heap()->CollectAllGarbage(true);
11791 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011792}
11793
11794
11795// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011796RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011797 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011798 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011799 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011800 }
11801 return Smi::FromInt(usage);
11802}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011803
11804
11805// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011806RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011807#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011808 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011809#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011811#endif
11812}
11813
11814
11815// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011816RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011817#ifdef LIVE_OBJECT_LIST
11818 return LiveObjectList::Capture();
11819#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011820 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011821#endif
11822}
11823
11824
11825// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011826RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011827#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011828 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011829 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830 return success ? isolate->heap()->true_value() :
11831 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011832#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011834#endif
11835}
11836
11837
11838// Generates the response to a debugger request for a dump of the objects
11839// contained in the difference between the captured live object lists
11840// specified by id1 and id2.
11841// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11842// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011843RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011844#ifdef LIVE_OBJECT_LIST
11845 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011846 CONVERT_SMI_ARG_CHECKED(id1, 0);
11847 CONVERT_SMI_ARG_CHECKED(id2, 1);
11848 CONVERT_SMI_ARG_CHECKED(start, 2);
11849 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011850 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11851 EnterDebugger enter_debugger;
11852 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11853#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011854 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011855#endif
11856}
11857
11858
11859// Gets the specified object as requested by the debugger.
11860// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011861RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011862#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011863 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011864 Object* result = LiveObjectList::GetObj(obj_id);
11865 return result;
11866#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011868#endif
11869}
11870
11871
11872// Gets the obj id for the specified address if valid.
11873// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011874RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011875#ifdef LIVE_OBJECT_LIST
11876 HandleScope scope;
11877 CONVERT_ARG_CHECKED(String, address, 0);
11878 Object* result = LiveObjectList::GetObjId(address);
11879 return result;
11880#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011882#endif
11883}
11884
11885
11886// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011887RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011888#ifdef LIVE_OBJECT_LIST
11889 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011890 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011891 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11892 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11893 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11894 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11895 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11896
11897 Handle<JSObject> instance_filter;
11898 if (args[1]->IsJSObject()) {
11899 instance_filter = args.at<JSObject>(1);
11900 }
11901 bool verbose = false;
11902 if (args[2]->IsBoolean()) {
11903 verbose = args[2]->IsTrue();
11904 }
11905 int start = 0;
11906 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011907 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011908 }
11909 int limit = Smi::kMaxValue;
11910 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011911 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011912 }
11913
11914 return LiveObjectList::GetObjRetainers(obj_id,
11915 instance_filter,
11916 verbose,
11917 start,
11918 limit,
11919 filter_obj);
11920#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011922#endif
11923}
11924
11925
11926// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011927RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011928#ifdef LIVE_OBJECT_LIST
11929 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011930 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
11931 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011932 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11933
11934 Handle<JSObject> instance_filter;
11935 if (args[2]->IsJSObject()) {
11936 instance_filter = args.at<JSObject>(2);
11937 }
11938
11939 Object* result =
11940 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11941 return result;
11942#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011944#endif
11945}
11946
11947
11948// Generates the response to a debugger request for a list of all
11949// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011950RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011951#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011952 CONVERT_SMI_ARG_CHECKED(start, 0);
11953 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011954 return LiveObjectList::Info(start, count);
11955#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011956 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011957#endif
11958}
11959
11960
11961// Gets a dump of the specified object as requested by the debugger.
11962// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011963RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011964#ifdef LIVE_OBJECT_LIST
11965 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011966 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011967 Object* result = LiveObjectList::PrintObj(obj_id);
11968 return result;
11969#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011971#endif
11972}
11973
11974
11975// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011976RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011977#ifdef LIVE_OBJECT_LIST
11978 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011979 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011980#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011981 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011982#endif
11983}
11984
11985
11986// Generates the response to a debugger request for a summary of the types
11987// of objects in the difference between the captured live object lists
11988// specified by id1 and id2.
11989// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11990// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011991RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011992#ifdef LIVE_OBJECT_LIST
11993 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011994 CONVERT_SMI_ARG_CHECKED(id1, 0);
11995 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011996 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11997
11998 EnterDebugger enter_debugger;
11999 return LiveObjectList::Summarize(id1, id2, filter_obj);
12000#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012001 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012002#endif
12003}
12004
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012005#endif // ENABLE_DEBUGGER_SUPPORT
12006
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012007
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012008#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012009RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012010 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000012011 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012012
12013 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000012014 CONVERT_CHECKED(Smi, smi_tag, args[1]);
12015 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012016 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012017}
12018
12019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012020RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012021 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000012022 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012023
12024 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000012025 CONVERT_CHECKED(Smi, smi_tag, args[1]);
12026 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012027 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012028}
12029
12030#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032// Finds the script object from the script data. NOTE: This operation uses
12033// heap traversal to find the function generated for the source position
12034// for the requested break point. For lazily compiled functions several heap
12035// traversals might be required rendering this operation as a rather slow
12036// operation. However for setting break points which is normally done through
12037// some kind of user interaction the performance is not crucial.
12038static Handle<Object> Runtime_GetScriptFromScriptName(
12039 Handle<String> script_name) {
12040 // Scan the heap for Script objects to find the script with the requested
12041 // script data.
12042 Handle<Script> script;
12043 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012044 HeapObject* obj = NULL;
12045 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046 // If a script is found check if it has the script data requested.
12047 if (obj->IsScript()) {
12048 if (Script::cast(obj)->name()->IsString()) {
12049 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12050 script = Handle<Script>(Script::cast(obj));
12051 }
12052 }
12053 }
12054 }
12055
12056 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012057 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012058
12059 // Return the script found.
12060 return GetScriptWrapper(script);
12061}
12062
12063
12064// Get the script object from script data. NOTE: Regarding performance
12065// see the NOTE for GetScriptFromScriptData.
12066// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012067RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012069
12070 ASSERT(args.length() == 1);
12071
12072 CONVERT_CHECKED(String, script_name, args[0]);
12073
12074 // Find the requested script.
12075 Handle<Object> result =
12076 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12077 return *result;
12078}
12079
12080
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012081// Determines whether the given stack frame should be displayed in
12082// a stack trace. The caller is the error constructor that asked
12083// for the stack trace to be collected. The first time a construct
12084// call to this function is encountered it is skipped. The seen_caller
12085// in/out parameter is used to remember if the caller has been seen
12086// yet.
12087static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12088 bool* seen_caller) {
12089 // Only display JS frames.
12090 if (!raw_frame->is_java_script())
12091 return false;
12092 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12093 Object* raw_fun = frame->function();
12094 // Not sure when this can happen but skip it just in case.
12095 if (!raw_fun->IsJSFunction())
12096 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012097 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012098 *seen_caller = true;
12099 return false;
12100 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012101 // Skip all frames until we've seen the caller. Also, skip the most
12102 // obvious builtin calls. Some builtin calls (such as Number.ADD
12103 // which is invoked using 'call') are very difficult to recognize
12104 // so we're leaving them in for now.
12105 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012106}
12107
12108
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012109// Collect the raw data for a stack trace. Returns an array of 4
12110// element segments each containing a receiver, function, code and
12111// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012112RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012113 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012114 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012115 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12116
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012117 HandleScope scope(isolate);
12118 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012119
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012120 limit = Max(limit, 0); // Ensure that limit is not negative.
12121 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012122 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012123 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012124
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012125 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012126 // If the caller parameter is a function we skip frames until we're
12127 // under it before starting to collect.
12128 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012129 int cursor = 0;
12130 int frames_seen = 0;
12131 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012132 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012133 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012134 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012135 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012136 // Set initial size to the maximum inlining level + 1 for the outermost
12137 // function.
12138 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012139 frame->Summarize(&frames);
12140 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012141 if (cursor + 4 > elements->length()) {
12142 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12143 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012144 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012145 for (int i = 0; i < cursor; i++) {
12146 new_elements->set(i, elements->get(i));
12147 }
12148 elements = new_elements;
12149 }
12150 ASSERT(cursor + 4 <= elements->length());
12151
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012152 Handle<Object> recv = frames[i].receiver();
12153 Handle<JSFunction> fun = frames[i].function();
12154 Handle<Code> code = frames[i].code();
12155 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012156 elements->set(cursor++, *recv);
12157 elements->set(cursor++, *fun);
12158 elements->set(cursor++, *code);
12159 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012160 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012161 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012162 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012163 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012164 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012165 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012166 return *result;
12167}
12168
12169
ager@chromium.org3811b432009-10-28 14:53:37 +000012170// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012171RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012172 ASSERT_EQ(args.length(), 0);
12173
12174 NoHandleAllocation ha;
12175
12176 const char* version_string = v8::V8::GetVersion();
12177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012178 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12179 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012180}
12181
12182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012183RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012185 OS::PrintError("abort: %s\n",
12186 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188 OS::Abort();
12189 UNREACHABLE();
12190 return NULL;
12191}
12192
12193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012194RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012195 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012196 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012197 Object* key = args[1];
12198
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012199 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012200 Object* o = cache->get(finger_index);
12201 if (o == key) {
12202 // The fastest case: hit the same place again.
12203 return cache->get(finger_index + 1);
12204 }
12205
12206 for (int i = finger_index - 2;
12207 i >= JSFunctionResultCache::kEntriesIndex;
12208 i -= 2) {
12209 o = cache->get(i);
12210 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012211 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012212 return cache->get(i + 1);
12213 }
12214 }
12215
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012216 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012217 ASSERT(size <= cache->length());
12218
12219 for (int i = size - 2; i > finger_index; i -= 2) {
12220 o = cache->get(i);
12221 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012222 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012223 return cache->get(i + 1);
12224 }
12225 }
12226
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012227 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012229
12230 Handle<JSFunctionResultCache> cache_handle(cache);
12231 Handle<Object> key_handle(key);
12232 Handle<Object> value;
12233 {
12234 Handle<JSFunction> factory(JSFunction::cast(
12235 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12236 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012238 // This handle is nor shared, nor used later, so it's safe.
12239 Object** argv[] = { key_handle.location() };
12240 bool pending_exception = false;
12241 value = Execution::Call(factory,
12242 receiver,
12243 1,
12244 argv,
12245 &pending_exception);
12246 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012247 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012248
12249#ifdef DEBUG
12250 cache_handle->JSFunctionResultCacheVerify();
12251#endif
12252
12253 // Function invocation may have cleared the cache. Reread all the data.
12254 finger_index = cache_handle->finger_index();
12255 size = cache_handle->size();
12256
12257 // If we have spare room, put new data into it, otherwise evict post finger
12258 // entry which is likely to be the least recently used.
12259 int index = -1;
12260 if (size < cache_handle->length()) {
12261 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12262 index = size;
12263 } else {
12264 index = finger_index + JSFunctionResultCache::kEntrySize;
12265 if (index == cache_handle->length()) {
12266 index = JSFunctionResultCache::kEntriesIndex;
12267 }
12268 }
12269
12270 ASSERT(index % 2 == 0);
12271 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12272 ASSERT(index < cache_handle->length());
12273
12274 cache_handle->set(index, *key_handle);
12275 cache_handle->set(index + 1, *value);
12276 cache_handle->set_finger_index(index);
12277
12278#ifdef DEBUG
12279 cache_handle->JSFunctionResultCacheVerify();
12280#endif
12281
12282 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012283}
12284
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012286RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012287 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012288 CONVERT_ARG_CHECKED(String, type, 0);
12289 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012290 return *isolate->factory()->NewJSMessageObject(
12291 type,
12292 arguments,
12293 0,
12294 0,
12295 isolate->factory()->undefined_value(),
12296 isolate->factory()->undefined_value(),
12297 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012298}
12299
12300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012301RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012302 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12303 return message->type();
12304}
12305
12306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012307RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012308 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12309 return message->arguments();
12310}
12311
12312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012313RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012314 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12315 return Smi::FromInt(message->start_position());
12316}
12317
12318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012319RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012320 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12321 return message->script();
12322}
12323
12324
kasper.lund44510672008-07-25 07:37:58 +000012325#ifdef DEBUG
12326// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12327// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012328RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012329 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012331#define COUNT_ENTRY(Name, argc, ressize) + 1
12332 int entry_count = 0
12333 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12334 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12335 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12336#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012337 Factory* factory = isolate->factory();
12338 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012339 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012340 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012341#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012342 { \
12343 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012344 Handle<String> name; \
12345 /* Inline runtime functions have an underscore in front of the name. */ \
12346 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012347 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012348 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12349 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012350 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012351 Vector<const char>(#Name, StrLength(#Name))); \
12352 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012353 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012354 pair_elements->set(0, *name); \
12355 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012356 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012357 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012359 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012360 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012361 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012362 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012363 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012364#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012365 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012366 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 return *result;
12368}
kasper.lund44510672008-07-25 07:37:58 +000012369#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012370
12371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012372RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012373 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012374 CONVERT_CHECKED(String, format, args[0]);
12375 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012376 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012377 LOGGER->LogRuntime(chars, elms);
12378 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012379}
12380
12381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012382RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012383 UNREACHABLE(); // implemented as macro in the parser
12384 return NULL;
12385}
12386
12387
12388// ----------------------------------------------------------------------------
12389// Implementation of Runtime
12390
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012391#define F(name, number_of_args, result_size) \
12392 { Runtime::k##name, Runtime::RUNTIME, #name, \
12393 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012394
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012395
12396#define I(name, number_of_args, result_size) \
12397 { Runtime::kInline##name, Runtime::INLINE, \
12398 "_" #name, NULL, number_of_args, result_size },
12399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012401 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012402 INLINE_FUNCTION_LIST(I)
12403 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012404};
12405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012407MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12408 Object* dictionary) {
12409 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012410 ASSERT(dictionary != NULL);
12411 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12412 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012413 Object* name_symbol;
12414 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012415 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012416 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12417 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012418 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012419 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12420 String::cast(name_symbol),
12421 Smi::FromInt(i),
12422 PropertyDetails(NONE, NORMAL));
12423 if (!maybe_dictionary->ToObject(&dictionary)) {
12424 // Non-recoverable failure. Calling code must restart heap
12425 // initialization.
12426 return maybe_dictionary;
12427 }
12428 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012429 }
12430 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012431}
12432
12433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012434const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12435 Heap* heap = name->GetHeap();
12436 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012437 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012439 int function_index = Smi::cast(smi_index)->value();
12440 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012441 }
12442 return NULL;
12443}
12444
12445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012446const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012447 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12448}
12449
12450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012451void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012452 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012453 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012454 if (failure->IsRetryAfterGC()) {
12455 // Try to do a garbage collection; ignore it if it fails. The C
12456 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012457 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012458 } else {
12459 // Handle last resort GC and make sure to allow future allocations
12460 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012461 isolate->counters()->gc_last_resort_from_js()->Increment();
12462 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012463 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012464}
12465
12466
12467} } // namespace v8::internal